17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52be60c5eSraf * Common Development and Distribution License (the "License"). 62be60c5eSraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21e8031f0aSraf 227c478bd9Sstevel@tonic-gate /* 2309ce0d4aSRoger A. Faulkner * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*0d045c0dSRobert Mustacchi * Copyright 2015, Joyent, Inc. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include "lint.h" 297c478bd9Sstevel@tonic-gate #include "thr_uberdata.h" 30d4204c85Sraf #include <sys/rtpriocntl.h> 3131db3c26Sraf #include <sys/sdt.h> 3231db3c26Sraf #include <atomic.h> 337c478bd9Sstevel@tonic-gate 34d4204c85Sraf #if defined(THREAD_DEBUG) 35d4204c85Sraf #define INCR32(x) (((x) != UINT32_MAX)? (x)++ : 0) 36d4204c85Sraf #define INCR(x) ((x)++) 37d4204c85Sraf #define DECR(x) ((x)--) 38d4204c85Sraf #define MAXINCR(m, x) ((m < ++x)? (m = x) : 0) 39d4204c85Sraf #else 40d4204c85Sraf #define INCR32(x) 41d4204c85Sraf #define INCR(x) 42d4204c85Sraf #define DECR(x) 43d4204c85Sraf #define MAXINCR(m, x) 44d4204c85Sraf #endif 45d4204c85Sraf 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * This mutex is initialized to be held by lwp#1. 487c478bd9Sstevel@tonic-gate * It is used to block a thread that has returned from a mutex_lock() 49883492d5Sraf * of a LOCK_PRIO_INHERIT mutex with an unrecoverable error. 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate mutex_t stall_mutex = DEFAULTMUTEX; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static int shared_mutex_held(mutex_t *); 54883492d5Sraf static int mutex_queuelock_adaptive(mutex_t *); 55883492d5Sraf static void mutex_wakeup_all(mutex_t *); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * Lock statistics support functions. 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate void 617c478bd9Sstevel@tonic-gate record_begin_hold(tdb_mutex_stats_t *msp) 627c478bd9Sstevel@tonic-gate { 637c478bd9Sstevel@tonic-gate tdb_incr(msp->mutex_lock); 647c478bd9Sstevel@tonic-gate msp->mutex_begin_hold = gethrtime(); 657c478bd9Sstevel@tonic-gate } 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate hrtime_t 687c478bd9Sstevel@tonic-gate record_hold_time(tdb_mutex_stats_t *msp) 697c478bd9Sstevel@tonic-gate { 707c478bd9Sstevel@tonic-gate hrtime_t now = gethrtime(); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate if (msp->mutex_begin_hold) 737c478bd9Sstevel@tonic-gate msp->mutex_hold_time += now - msp->mutex_begin_hold; 747c478bd9Sstevel@tonic-gate msp->mutex_begin_hold = 0; 757c478bd9Sstevel@tonic-gate return (now); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Called once at library initialization. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate void 827c478bd9Sstevel@tonic-gate mutex_setup(void) 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate if (set_lock_byte(&stall_mutex.mutex_lockw)) 857c478bd9Sstevel@tonic-gate thr_panic("mutex_setup() cannot acquire stall_mutex"); 867c478bd9Sstevel@tonic-gate stall_mutex.mutex_owner = (uintptr_t)curthread; 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 905d1dd9a9Sraf * The default spin count of 1000 is experimentally determined. 915d1dd9a9Sraf * On sun4u machines with any number of processors it could be raised 927c478bd9Sstevel@tonic-gate * to 10,000 but that (experimentally) makes almost no difference. 935d1dd9a9Sraf * The environment variable: 947c478bd9Sstevel@tonic-gate * _THREAD_ADAPTIVE_SPIN=count 955d1dd9a9Sraf * can be used to override and set the count in the range [0 .. 1,000,000]. 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate int thread_adaptive_spin = 1000; 987c478bd9Sstevel@tonic-gate uint_t thread_max_spinners = 100; 997c478bd9Sstevel@tonic-gate int thread_queue_verify = 0; 1007c478bd9Sstevel@tonic-gate static int ncpus; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Distinguish spinning for queue locks from spinning for regular locks. 1045d1dd9a9Sraf * We try harder to acquire queue locks by spinning. 1057c478bd9Sstevel@tonic-gate * The environment variable: 1067c478bd9Sstevel@tonic-gate * _THREAD_QUEUE_SPIN=count 1077c478bd9Sstevel@tonic-gate * can be used to override and set the count in the range [0 .. 1,000,000]. 1087c478bd9Sstevel@tonic-gate */ 1095d1dd9a9Sraf int thread_queue_spin = 10000; 1107c478bd9Sstevel@tonic-gate 111883492d5Sraf #define ALL_ATTRIBUTES \ 112883492d5Sraf (LOCK_RECURSIVE | LOCK_ERRORCHECK | \ 113883492d5Sraf LOCK_PRIO_INHERIT | LOCK_PRIO_PROTECT | \ 114883492d5Sraf LOCK_ROBUST) 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* 117883492d5Sraf * 'type' can be one of USYNC_THREAD, USYNC_PROCESS, or USYNC_PROCESS_ROBUST, 118883492d5Sraf * augmented by zero or more the flags: 119883492d5Sraf * LOCK_RECURSIVE 120883492d5Sraf * LOCK_ERRORCHECK 121883492d5Sraf * LOCK_PRIO_INHERIT 122883492d5Sraf * LOCK_PRIO_PROTECT 123883492d5Sraf * LOCK_ROBUST 1247c478bd9Sstevel@tonic-gate */ 1257257d1b4Sraf #pragma weak _mutex_init = mutex_init 1267c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 1277c478bd9Sstevel@tonic-gate int 1287257d1b4Sraf mutex_init(mutex_t *mp, int type, void *arg) 1297c478bd9Sstevel@tonic-gate { 130883492d5Sraf int basetype = (type & ~ALL_ATTRIBUTES); 131d4204c85Sraf const pcclass_t *pccp; 132883492d5Sraf int error = 0; 133d4204c85Sraf int ceil; 1347c478bd9Sstevel@tonic-gate 135883492d5Sraf if (basetype == USYNC_PROCESS_ROBUST) { 136883492d5Sraf /* 137883492d5Sraf * USYNC_PROCESS_ROBUST is a deprecated historical type. 138883492d5Sraf * We change it into (USYNC_PROCESS | LOCK_ROBUST) but 139883492d5Sraf * retain the USYNC_PROCESS_ROBUST flag so we can return 140883492d5Sraf * ELOCKUNMAPPED when necessary (only USYNC_PROCESS_ROBUST 141883492d5Sraf * mutexes will ever draw ELOCKUNMAPPED). 142883492d5Sraf */ 143883492d5Sraf type |= (USYNC_PROCESS | LOCK_ROBUST); 144883492d5Sraf basetype = USYNC_PROCESS; 145883492d5Sraf } 146883492d5Sraf 147d4204c85Sraf if (type & LOCK_PRIO_PROTECT) 148d4204c85Sraf pccp = get_info_by_policy(SCHED_FIFO); 149d4204c85Sraf if ((basetype != USYNC_THREAD && basetype != USYNC_PROCESS) || 150883492d5Sraf (type & (LOCK_PRIO_INHERIT | LOCK_PRIO_PROTECT)) 151d4204c85Sraf == (LOCK_PRIO_INHERIT | LOCK_PRIO_PROTECT) || 152d4204c85Sraf ((type & LOCK_PRIO_PROTECT) && 153d4204c85Sraf ((ceil = *(int *)arg) < pccp->pcc_primin || 154d4204c85Sraf ceil > pccp->pcc_primax))) { 155883492d5Sraf error = EINVAL; 156883492d5Sraf } else if (type & LOCK_ROBUST) { 157883492d5Sraf /* 158883492d5Sraf * Callers of mutex_init() with the LOCK_ROBUST attribute 159883492d5Sraf * are required to pass an initially all-zero mutex. 160883492d5Sraf * Multiple calls to mutex_init() are allowed; all but 161883492d5Sraf * the first return EBUSY. A call to mutex_init() is 162883492d5Sraf * allowed to make an inconsistent robust lock consistent 163883492d5Sraf * (for historical usage, even though the proper interface 164883492d5Sraf * for this is mutex_consistent()). Note that we use 165883492d5Sraf * atomic_or_16() to set the LOCK_INITED flag so as 166883492d5Sraf * not to disturb surrounding bits (LOCK_OWNERDEAD, etc). 167883492d5Sraf */ 168883492d5Sraf if (!(mp->mutex_flag & LOCK_INITED)) { 169883492d5Sraf mp->mutex_type = (uint8_t)type; 1707257d1b4Sraf atomic_or_16(&mp->mutex_flag, LOCK_INITED); 171883492d5Sraf mp->mutex_magic = MUTEX_MAGIC; 172883492d5Sraf } else if (type != mp->mutex_type || 173d4204c85Sraf ((type & LOCK_PRIO_PROTECT) && mp->mutex_ceiling != ceil)) { 174883492d5Sraf error = EINVAL; 1757257d1b4Sraf } else if (mutex_consistent(mp) != 0) { 176883492d5Sraf error = EBUSY; 177883492d5Sraf } 178883492d5Sraf /* register a process robust mutex with the kernel */ 179883492d5Sraf if (basetype == USYNC_PROCESS) 180883492d5Sraf register_lock(mp); 181883492d5Sraf } else { 1828cd45542Sraf (void) memset(mp, 0, sizeof (*mp)); 1837c478bd9Sstevel@tonic-gate mp->mutex_type = (uint8_t)type; 1847c478bd9Sstevel@tonic-gate mp->mutex_flag = LOCK_INITED; 1857c478bd9Sstevel@tonic-gate mp->mutex_magic = MUTEX_MAGIC; 186883492d5Sraf } 187883492d5Sraf 188d4204c85Sraf if (error == 0 && (type & LOCK_PRIO_PROTECT)) { 189d4204c85Sraf mp->mutex_ceiling = ceil; 190d4204c85Sraf } 191883492d5Sraf 1927c5714f6Sraf /* 1937c5714f6Sraf * This should be at the beginning of the function, 1947c5714f6Sraf * but for the sake of old broken applications that 1957c5714f6Sraf * do not have proper alignment for their mutexes 1967c5714f6Sraf * (and don't check the return code from mutex_init), 1977c5714f6Sraf * we put it here, after initializing the mutex regardless. 1987c5714f6Sraf */ 1997c5714f6Sraf if (error == 0 && 2007c5714f6Sraf ((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) && 2017c5714f6Sraf curthread->ul_misaligned == 0) 2027c5714f6Sraf error = EINVAL; 2037c5714f6Sraf 2047c478bd9Sstevel@tonic-gate return (error); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 208d4204c85Sraf * Delete mp from list of ceiling mutexes owned by curthread. 2097c478bd9Sstevel@tonic-gate * Return 1 if the head of the chain was updated. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate int 2127c478bd9Sstevel@tonic-gate _ceil_mylist_del(mutex_t *mp) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 2157c478bd9Sstevel@tonic-gate mxchain_t **mcpp; 2167c478bd9Sstevel@tonic-gate mxchain_t *mcp; 2177c478bd9Sstevel@tonic-gate 218d4204c85Sraf for (mcpp = &self->ul_mxchain; 219d4204c85Sraf (mcp = *mcpp) != NULL; 220d4204c85Sraf mcpp = &mcp->mxchain_next) { 221d4204c85Sraf if (mcp->mxchain_mx == mp) { 2227c478bd9Sstevel@tonic-gate *mcpp = mcp->mxchain_next; 2237c478bd9Sstevel@tonic-gate lfree(mcp, sizeof (*mcp)); 2247c478bd9Sstevel@tonic-gate return (mcpp == &self->ul_mxchain); 2257c478bd9Sstevel@tonic-gate } 226d4204c85Sraf } 227d4204c85Sraf return (0); 228d4204c85Sraf } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 231d4204c85Sraf * Add mp to the list of ceiling mutexes owned by curthread. 2327c478bd9Sstevel@tonic-gate * Return ENOMEM if no memory could be allocated. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate int 2357c478bd9Sstevel@tonic-gate _ceil_mylist_add(mutex_t *mp) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 2387c478bd9Sstevel@tonic-gate mxchain_t *mcp; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if ((mcp = lmalloc(sizeof (*mcp))) == NULL) 2417c478bd9Sstevel@tonic-gate return (ENOMEM); 2427c478bd9Sstevel@tonic-gate mcp->mxchain_mx = mp; 2437c478bd9Sstevel@tonic-gate mcp->mxchain_next = self->ul_mxchain; 2447c478bd9Sstevel@tonic-gate self->ul_mxchain = mcp; 2457c478bd9Sstevel@tonic-gate return (0); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 249d4204c85Sraf * Helper function for _ceil_prio_inherit() and _ceil_prio_waive(), below. 250d4204c85Sraf */ 251d4204c85Sraf static void 252d4204c85Sraf set_rt_priority(ulwp_t *self, int prio) 253d4204c85Sraf { 254d4204c85Sraf pcparms_t pcparm; 255d4204c85Sraf 256d4204c85Sraf pcparm.pc_cid = self->ul_rtclassid; 257d4204c85Sraf ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs = RT_NOCHANGE; 258d4204c85Sraf ((rtparms_t *)pcparm.pc_clparms)->rt_pri = prio; 2598cd45542Sraf (void) priocntl(P_LWPID, self->ul_lwpid, PC_SETPARMS, &pcparm); 260d4204c85Sraf } 261d4204c85Sraf 262d4204c85Sraf /* 263d4204c85Sraf * Inherit priority from ceiling. 264d4204c85Sraf * This changes the effective priority, not the assigned priority. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate void 267d4204c85Sraf _ceil_prio_inherit(int prio) 2687c478bd9Sstevel@tonic-gate { 2697c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 2707c478bd9Sstevel@tonic-gate 271d4204c85Sraf self->ul_epri = prio; 272d4204c85Sraf set_rt_priority(self, prio); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * Waive inherited ceiling priority. Inherit from head of owned ceiling locks 2777c478bd9Sstevel@tonic-gate * if holding at least one ceiling lock. If no ceiling locks are held at this 2787c478bd9Sstevel@tonic-gate * point, disinherit completely, reverting back to assigned priority. 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate void 2817c478bd9Sstevel@tonic-gate _ceil_prio_waive(void) 2827c478bd9Sstevel@tonic-gate { 2837c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 284d4204c85Sraf mxchain_t *mcp = self->ul_mxchain; 285d4204c85Sraf int prio; 2867c478bd9Sstevel@tonic-gate 287d4204c85Sraf if (mcp == NULL) { 288d4204c85Sraf prio = self->ul_pri; 289d4204c85Sraf self->ul_epri = 0; 2907c478bd9Sstevel@tonic-gate } else { 291d4204c85Sraf prio = mcp->mxchain_mx->mutex_ceiling; 292d4204c85Sraf self->ul_epri = prio; 2937c478bd9Sstevel@tonic-gate } 294d4204c85Sraf set_rt_priority(self, prio); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2985d1dd9a9Sraf * Clear the lock byte. Retain the waiters byte and the spinners byte. 2995d1dd9a9Sraf * Return the old value of the lock word. 3005d1dd9a9Sraf */ 3015d1dd9a9Sraf static uint32_t 3025d1dd9a9Sraf clear_lockbyte(volatile uint32_t *lockword) 3035d1dd9a9Sraf { 3045d1dd9a9Sraf uint32_t old; 3055d1dd9a9Sraf uint32_t new; 3065d1dd9a9Sraf 3075d1dd9a9Sraf do { 3085d1dd9a9Sraf old = *lockword; 3095d1dd9a9Sraf new = old & ~LOCKMASK; 3105d1dd9a9Sraf } while (atomic_cas_32(lockword, old, new) != old); 3115d1dd9a9Sraf 3125d1dd9a9Sraf return (old); 3135d1dd9a9Sraf } 3145d1dd9a9Sraf 3155d1dd9a9Sraf /* 31631db3c26Sraf * Same as clear_lockbyte(), but operates on mutex_lockword64. 31731db3c26Sraf * The mutex_ownerpid field is cleared along with the lock byte. 31831db3c26Sraf */ 31931db3c26Sraf static uint64_t 32031db3c26Sraf clear_lockbyte64(volatile uint64_t *lockword64) 32131db3c26Sraf { 32231db3c26Sraf uint64_t old; 32331db3c26Sraf uint64_t new; 32431db3c26Sraf 32531db3c26Sraf do { 32631db3c26Sraf old = *lockword64; 32731db3c26Sraf new = old & ~LOCKMASK64; 32831db3c26Sraf } while (atomic_cas_64(lockword64, old, new) != old); 32931db3c26Sraf 33031db3c26Sraf return (old); 33131db3c26Sraf } 33231db3c26Sraf 33331db3c26Sraf /* 33431db3c26Sraf * Similar to set_lock_byte(), which only tries to set the lock byte. 3357c5714f6Sraf * Here, we attempt to set the lock byte AND the mutex_ownerpid, keeping 3367c5714f6Sraf * the remaining bytes constant. This atomic operation is required for the 3377c5714f6Sraf * correctness of process-shared robust locks, otherwise there would be 3387c5714f6Sraf * a window or vulnerability in which the lock byte had been set but the 3397c5714f6Sraf * mutex_ownerpid had not yet been set. If the process were to die in 3407c5714f6Sraf * this window of vulnerability (due to some other thread calling exit() 3417c5714f6Sraf * or the process receiving a fatal signal), the mutex would be left locked 3427c5714f6Sraf * but without a process-ID to determine which process was holding the lock. 3437c5714f6Sraf * The kernel would then be unable to mark the robust mutex as LOCK_OWNERDEAD 3447c5714f6Sraf * when the process died. For all other cases of process-shared locks, this 3457c5714f6Sraf * operation is just a convenience, for the sake of common code. 3467c5714f6Sraf * 3477c5714f6Sraf * This operation requires process-shared robust locks to be properly 3487c5714f6Sraf * aligned on an 8-byte boundary, at least on sparc machines, lest the 3497c5714f6Sraf * operation incur an alignment fault. This is automatic when locks 3507c5714f6Sraf * are declared properly using the mutex_t or pthread_mutex_t data types 3517c5714f6Sraf * and the application does not allocate dynamic memory on less than an 3527c5714f6Sraf * 8-byte boundary. See the 'horrible hack' comments below for cases 3537c5714f6Sraf * dealing with such broken applications. 35431db3c26Sraf */ 35531db3c26Sraf static int 35631db3c26Sraf set_lock_byte64(volatile uint64_t *lockword64, pid_t ownerpid) 35731db3c26Sraf { 35831db3c26Sraf uint64_t old; 35931db3c26Sraf uint64_t new; 36031db3c26Sraf 36131db3c26Sraf old = *lockword64 & ~LOCKMASK64; 36231db3c26Sraf new = old | ((uint64_t)(uint_t)ownerpid << PIDSHIFT) | LOCKBYTE64; 36331db3c26Sraf if (atomic_cas_64(lockword64, old, new) == old) 36431db3c26Sraf return (LOCKCLEAR); 36531db3c26Sraf 36631db3c26Sraf return (LOCKSET); 36731db3c26Sraf } 36831db3c26Sraf 36931db3c26Sraf /* 3705d1dd9a9Sraf * Increment the spinners count in the mutex lock word. 3715d1dd9a9Sraf * Return 0 on success. Return -1 if the count would overflow. 3725d1dd9a9Sraf */ 3735d1dd9a9Sraf static int 3745d1dd9a9Sraf spinners_incr(volatile uint32_t *lockword, uint8_t max_spinners) 3755d1dd9a9Sraf { 3765d1dd9a9Sraf uint32_t old; 3775d1dd9a9Sraf uint32_t new; 3785d1dd9a9Sraf 3795d1dd9a9Sraf do { 3805d1dd9a9Sraf old = *lockword; 3815d1dd9a9Sraf if (((old & SPINNERMASK) >> SPINNERSHIFT) >= max_spinners) 3825d1dd9a9Sraf return (-1); 3835d1dd9a9Sraf new = old + (1 << SPINNERSHIFT); 3845d1dd9a9Sraf } while (atomic_cas_32(lockword, old, new) != old); 3855d1dd9a9Sraf 3865d1dd9a9Sraf return (0); 3875d1dd9a9Sraf } 3885d1dd9a9Sraf 3895d1dd9a9Sraf /* 3905d1dd9a9Sraf * Decrement the spinners count in the mutex lock word. 3915d1dd9a9Sraf * Return the new value of the lock word. 3925d1dd9a9Sraf */ 3935d1dd9a9Sraf static uint32_t 3945d1dd9a9Sraf spinners_decr(volatile uint32_t *lockword) 3955d1dd9a9Sraf { 3965d1dd9a9Sraf uint32_t old; 3975d1dd9a9Sraf uint32_t new; 3985d1dd9a9Sraf 3995d1dd9a9Sraf do { 4005d1dd9a9Sraf new = old = *lockword; 4015d1dd9a9Sraf if (new & SPINNERMASK) 4025d1dd9a9Sraf new -= (1 << SPINNERSHIFT); 4035d1dd9a9Sraf } while (atomic_cas_32(lockword, old, new) != old); 4045d1dd9a9Sraf 4055d1dd9a9Sraf return (new); 4065d1dd9a9Sraf } 4075d1dd9a9Sraf 4085d1dd9a9Sraf /* 4097c478bd9Sstevel@tonic-gate * Non-preemptive spin locks. Used by queue_lock(). 4107c478bd9Sstevel@tonic-gate * No lock statistics are gathered for these locks. 4115d1dd9a9Sraf * No DTrace probes are provided for these locks. 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate void 4147c478bd9Sstevel@tonic-gate spin_lock_set(mutex_t *mp) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate no_preempt(self); 4197c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) == 0) { 4207c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 4217c478bd9Sstevel@tonic-gate return; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * Spin for a while, attempting to acquire the lock. 4257c478bd9Sstevel@tonic-gate */ 426d4204c85Sraf INCR32(self->ul_spin_lock_spin); 4277c478bd9Sstevel@tonic-gate if (mutex_queuelock_adaptive(mp) == 0 || 4287c478bd9Sstevel@tonic-gate set_lock_byte(&mp->mutex_lockw) == 0) { 4297c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 4307c478bd9Sstevel@tonic-gate return; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Try harder if we were previously at a no premption level. 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate if (self->ul_preempt > 1) { 436d4204c85Sraf INCR32(self->ul_spin_lock_spin2); 4377c478bd9Sstevel@tonic-gate if (mutex_queuelock_adaptive(mp) == 0 || 4387c478bd9Sstevel@tonic-gate set_lock_byte(&mp->mutex_lockw) == 0) { 4397c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 4407c478bd9Sstevel@tonic-gate return; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * Give up and block in the kernel for the mutex. 4457c478bd9Sstevel@tonic-gate */ 446d4204c85Sraf INCR32(self->ul_spin_lock_sleep); 447db94676fSRoger A. Faulkner (void) ___lwp_mutex_timedlock(mp, NULL, self); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate void 4517c478bd9Sstevel@tonic-gate spin_lock_clear(mutex_t *mp) 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate mp->mutex_owner = 0; 45641efec22Sraf if (atomic_swap_32(&mp->mutex_lockword, 0) & WAITERMASK) { 457883492d5Sraf (void) ___lwp_mutex_wakeup(mp, 0); 458d4204c85Sraf INCR32(self->ul_spin_lock_wakeup); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate preempt(self); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Allocate the sleep queue hash table. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate void 4677c478bd9Sstevel@tonic-gate queue_alloc(void) 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 4707c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 471d4204c85Sraf queue_head_t *qp; 4727c478bd9Sstevel@tonic-gate void *data; 4737c478bd9Sstevel@tonic-gate int i; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * No locks are needed; we call here only when single-threaded. 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate ASSERT(self == udp->ulwp_one); 4797c478bd9Sstevel@tonic-gate ASSERT(!udp->uberflags.uf_mt); 4808cd45542Sraf if ((data = mmap(NULL, 2 * QHASHSIZE * sizeof (queue_head_t), 4817c478bd9Sstevel@tonic-gate PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0)) 4827c478bd9Sstevel@tonic-gate == MAP_FAILED) 4837c478bd9Sstevel@tonic-gate thr_panic("cannot allocate thread queue_head table"); 484d4204c85Sraf udp->queue_head = qp = (queue_head_t *)data; 485d4204c85Sraf for (i = 0; i < 2 * QHASHSIZE; qp++, i++) { 486d4204c85Sraf qp->qh_type = (i < QHASHSIZE)? MX : CV; 487d4204c85Sraf qp->qh_lock.mutex_flag = LOCK_INITED; 488d4204c85Sraf qp->qh_lock.mutex_magic = MUTEX_MAGIC; 489d4204c85Sraf qp->qh_hlist = &qp->qh_def_root; 490d4204c85Sraf #if defined(THREAD_DEBUG) 491d4204c85Sraf qp->qh_hlen = 1; 492d4204c85Sraf qp->qh_hmax = 1; 493d4204c85Sraf #endif 494883492d5Sraf } 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate #if defined(THREAD_DEBUG) 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * Debugging: verify correctness of a sleep queue. 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate void 5037c478bd9Sstevel@tonic-gate QVERIFY(queue_head_t *qp) 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 5067c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 507d4204c85Sraf queue_root_t *qrp; 5087c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 5097c478bd9Sstevel@tonic-gate ulwp_t *prev; 5107c478bd9Sstevel@tonic-gate uint_t index; 511d4204c85Sraf uint32_t cnt; 5127c478bd9Sstevel@tonic-gate char qtype; 5137c478bd9Sstevel@tonic-gate void *wchan; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate ASSERT(qp >= udp->queue_head && (qp - udp->queue_head) < 2 * QHASHSIZE); 5167c478bd9Sstevel@tonic-gate ASSERT(MUTEX_OWNED(&qp->qh_lock, self)); 517d4204c85Sraf for (cnt = 0, qrp = qp->qh_hlist; qrp != NULL; qrp = qrp->qr_next) { 518d4204c85Sraf cnt++; 519d4204c85Sraf ASSERT((qrp->qr_head != NULL && qrp->qr_tail != NULL) || 520d4204c85Sraf (qrp->qr_head == NULL && qrp->qr_tail == NULL)); 521d4204c85Sraf } 522d4204c85Sraf ASSERT(qp->qh_hlen == cnt && qp->qh_hmax >= cnt); 523d4204c85Sraf qtype = ((qp - udp->queue_head) < QHASHSIZE)? MX : CV; 524d4204c85Sraf ASSERT(qp->qh_type == qtype); 5257c478bd9Sstevel@tonic-gate if (!thread_queue_verify) 5267c478bd9Sstevel@tonic-gate return; 5277c478bd9Sstevel@tonic-gate /* real expensive stuff, only for _THREAD_QUEUE_VERIFY */ 528d4204c85Sraf for (cnt = 0, qrp = qp->qh_hlist; qrp != NULL; qrp = qrp->qr_next) { 529d4204c85Sraf for (prev = NULL, ulwp = qrp->qr_head; ulwp != NULL; 530d4204c85Sraf prev = ulwp, ulwp = ulwp->ul_link) { 531d4204c85Sraf cnt++; 532d4204c85Sraf if (ulwp->ul_writer) 533d4204c85Sraf ASSERT(prev == NULL || prev->ul_writer); 5347c478bd9Sstevel@tonic-gate ASSERT(ulwp->ul_qtype == qtype); 5357c478bd9Sstevel@tonic-gate ASSERT(ulwp->ul_wchan != NULL); 5367c478bd9Sstevel@tonic-gate ASSERT(ulwp->ul_sleepq == qp); 5377c478bd9Sstevel@tonic-gate wchan = ulwp->ul_wchan; 538d4204c85Sraf ASSERT(qrp->qr_wchan == wchan); 5397c478bd9Sstevel@tonic-gate index = QUEUE_HASH(wchan, qtype); 5407c478bd9Sstevel@tonic-gate ASSERT(&udp->queue_head[index] == qp); 5417c478bd9Sstevel@tonic-gate } 542d4204c85Sraf ASSERT(qrp->qr_tail == prev); 543d4204c85Sraf } 5447c478bd9Sstevel@tonic-gate ASSERT(qp->qh_qlen == cnt); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate #else /* THREAD_DEBUG */ 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate #define QVERIFY(qp) 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate #endif /* THREAD_DEBUG */ 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * Acquire a queue head. 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate queue_head_t * 5577c478bd9Sstevel@tonic-gate queue_lock(void *wchan, int qtype) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate uberdata_t *udp = curthread->ul_uberdata; 5607c478bd9Sstevel@tonic-gate queue_head_t *qp; 561d4204c85Sraf queue_root_t *qrp; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate ASSERT(qtype == MX || qtype == CV); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * It is possible that we could be called while still single-threaded. 5677c478bd9Sstevel@tonic-gate * If so, we call queue_alloc() to allocate the queue_head[] array. 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate if ((qp = udp->queue_head) == NULL) { 5707c478bd9Sstevel@tonic-gate queue_alloc(); 5717c478bd9Sstevel@tonic-gate qp = udp->queue_head; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate qp += QUEUE_HASH(wchan, qtype); 5747c478bd9Sstevel@tonic-gate spin_lock_set(&qp->qh_lock); 575d4204c85Sraf for (qrp = qp->qh_hlist; qrp != NULL; qrp = qrp->qr_next) 576d4204c85Sraf if (qrp->qr_wchan == wchan) 577d4204c85Sraf break; 578d4204c85Sraf if (qrp == NULL && qp->qh_def_root.qr_head == NULL) { 579d4204c85Sraf /* the default queue root is available; use it */ 580d4204c85Sraf qrp = &qp->qh_def_root; 581d4204c85Sraf qrp->qr_wchan = wchan; 582d4204c85Sraf ASSERT(qrp->qr_next == NULL); 583d4204c85Sraf ASSERT(qrp->qr_tail == NULL && 584d4204c85Sraf qrp->qr_rtcount == 0 && qrp->qr_qlen == 0); 585d4204c85Sraf } 586d4204c85Sraf qp->qh_wchan = wchan; /* valid until queue_unlock() is called */ 587d4204c85Sraf qp->qh_root = qrp; /* valid until queue_unlock() is called */ 588d4204c85Sraf INCR32(qp->qh_lockcount); 5897c478bd9Sstevel@tonic-gate QVERIFY(qp); 5907c478bd9Sstevel@tonic-gate return (qp); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Release a queue head. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate void 5977c478bd9Sstevel@tonic-gate queue_unlock(queue_head_t *qp) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate QVERIFY(qp); 6007c478bd9Sstevel@tonic-gate spin_lock_clear(&qp->qh_lock); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * For rwlock queueing, we must queue writers ahead of readers of the 6057c478bd9Sstevel@tonic-gate * same priority. We do this by making writers appear to have a half 6067c478bd9Sstevel@tonic-gate * point higher priority for purposes of priority comparisons below. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate #define CMP_PRIO(ulwp) ((real_priority(ulwp) << 1) + (ulwp)->ul_writer) 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate void 611d4204c85Sraf enqueue(queue_head_t *qp, ulwp_t *ulwp, int force_fifo) 6127c478bd9Sstevel@tonic-gate { 613d4204c85Sraf queue_root_t *qrp; 6147c478bd9Sstevel@tonic-gate ulwp_t **ulwpp; 6157c478bd9Sstevel@tonic-gate ulwp_t *next; 6167c478bd9Sstevel@tonic-gate int pri = CMP_PRIO(ulwp); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate ASSERT(MUTEX_OWNED(&qp->qh_lock, curthread)); 6197c478bd9Sstevel@tonic-gate ASSERT(ulwp->ul_sleepq != qp); 6207c478bd9Sstevel@tonic-gate 621d4204c85Sraf if ((qrp = qp->qh_root) == NULL) { 622d4204c85Sraf /* use the thread's queue root for the linkage */ 623d4204c85Sraf qrp = &ulwp->ul_queue_root; 624d4204c85Sraf qrp->qr_next = qp->qh_hlist; 625d4204c85Sraf qrp->qr_prev = NULL; 626d4204c85Sraf qrp->qr_head = NULL; 627d4204c85Sraf qrp->qr_tail = NULL; 628d4204c85Sraf qrp->qr_wchan = qp->qh_wchan; 629d4204c85Sraf qrp->qr_rtcount = 0; 630d4204c85Sraf qrp->qr_qlen = 0; 631d4204c85Sraf qrp->qr_qmax = 0; 632d4204c85Sraf qp->qh_hlist->qr_prev = qrp; 633d4204c85Sraf qp->qh_hlist = qrp; 634d4204c85Sraf qp->qh_root = qrp; 635d4204c85Sraf MAXINCR(qp->qh_hmax, qp->qh_hlen); 636d4204c85Sraf } 637d4204c85Sraf 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * LIFO queue ordering is unfair and can lead to starvation, 6407c478bd9Sstevel@tonic-gate * but it gives better performance for heavily contended locks. 6417c478bd9Sstevel@tonic-gate * We use thread_queue_fifo (range is 0..8) to determine 6427c478bd9Sstevel@tonic-gate * the frequency of FIFO vs LIFO queuing: 6437c478bd9Sstevel@tonic-gate * 0 : every 256th time (almost always LIFO) 6447c478bd9Sstevel@tonic-gate * 1 : every 128th time 6457c478bd9Sstevel@tonic-gate * 2 : every 64th time 6467c478bd9Sstevel@tonic-gate * 3 : every 32nd time 6477c478bd9Sstevel@tonic-gate * 4 : every 16th time (the default value, mostly LIFO) 6487c478bd9Sstevel@tonic-gate * 5 : every 8th time 6497c478bd9Sstevel@tonic-gate * 6 : every 4th time 6507c478bd9Sstevel@tonic-gate * 7 : every 2nd time 6517c478bd9Sstevel@tonic-gate * 8 : every time (never LIFO, always FIFO) 6527c478bd9Sstevel@tonic-gate * Note that there is always some degree of FIFO ordering. 6537c478bd9Sstevel@tonic-gate * This breaks live lock conditions that occur in applications 6547c478bd9Sstevel@tonic-gate * that are written assuming (incorrectly) that threads acquire 6557c478bd9Sstevel@tonic-gate * locks fairly, that is, in roughly round-robin order. 656d4204c85Sraf * In any event, the queue is maintained in kernel priority order. 6577c478bd9Sstevel@tonic-gate * 658d4204c85Sraf * If force_fifo is non-zero, fifo queueing is forced. 6597c478bd9Sstevel@tonic-gate * SUSV3 requires this for semaphores. 6607c478bd9Sstevel@tonic-gate */ 661d4204c85Sraf if (qrp->qr_head == NULL) { 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * The queue is empty. LIFO/FIFO doesn't matter. 6647c478bd9Sstevel@tonic-gate */ 665d4204c85Sraf ASSERT(qrp->qr_tail == NULL); 666d4204c85Sraf ulwpp = &qrp->qr_head; 667d4204c85Sraf } else if (force_fifo | 668d4204c85Sraf (((++qp->qh_qcnt << curthread->ul_queue_fifo) & 0xff) == 0)) { 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * Enqueue after the last thread whose priority is greater 6717c478bd9Sstevel@tonic-gate * than or equal to the priority of the thread being queued. 6727c478bd9Sstevel@tonic-gate * Attempt first to go directly onto the tail of the queue. 6737c478bd9Sstevel@tonic-gate */ 674d4204c85Sraf if (pri <= CMP_PRIO(qrp->qr_tail)) 675d4204c85Sraf ulwpp = &qrp->qr_tail->ul_link; 6767c478bd9Sstevel@tonic-gate else { 677d4204c85Sraf for (ulwpp = &qrp->qr_head; (next = *ulwpp) != NULL; 6787c478bd9Sstevel@tonic-gate ulwpp = &next->ul_link) 6797c478bd9Sstevel@tonic-gate if (pri > CMP_PRIO(next)) 6807c478bd9Sstevel@tonic-gate break; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate } else { 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * Enqueue before the first thread whose priority is less 6857c478bd9Sstevel@tonic-gate * than or equal to the priority of the thread being queued. 6867c478bd9Sstevel@tonic-gate * Hopefully we can go directly onto the head of the queue. 6877c478bd9Sstevel@tonic-gate */ 688d4204c85Sraf for (ulwpp = &qrp->qr_head; (next = *ulwpp) != NULL; 6897c478bd9Sstevel@tonic-gate ulwpp = &next->ul_link) 6907c478bd9Sstevel@tonic-gate if (pri >= CMP_PRIO(next)) 6917c478bd9Sstevel@tonic-gate break; 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate if ((ulwp->ul_link = *ulwpp) == NULL) 694d4204c85Sraf qrp->qr_tail = ulwp; 6957c478bd9Sstevel@tonic-gate *ulwpp = ulwp; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate ulwp->ul_sleepq = qp; 698d4204c85Sraf ulwp->ul_wchan = qp->qh_wchan; 699d4204c85Sraf ulwp->ul_qtype = qp->qh_type; 700d4204c85Sraf if ((ulwp->ul_schedctl != NULL && 701d4204c85Sraf ulwp->ul_schedctl->sc_cid == ulwp->ul_rtclassid) | 702d4204c85Sraf ulwp->ul_pilocks) { 703d4204c85Sraf ulwp->ul_rtqueued = 1; 704d4204c85Sraf qrp->qr_rtcount++; 705d4204c85Sraf } 706d4204c85Sraf MAXINCR(qrp->qr_qmax, qrp->qr_qlen); 707d4204c85Sraf MAXINCR(qp->qh_qmax, qp->qh_qlen); 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* 711d4204c85Sraf * Helper function for queue_slot() and queue_slot_rt(). 712d4204c85Sraf * Try to find a non-suspended thread on the queue. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate static ulwp_t ** 715d4204c85Sraf queue_slot_runnable(ulwp_t **ulwpp, ulwp_t **prevp, int rt) 7167c478bd9Sstevel@tonic-gate { 7177c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 718d4204c85Sraf ulwp_t **foundpp = NULL; 719d4204c85Sraf int priority = -1; 720d4204c85Sraf ulwp_t *prev; 721d4204c85Sraf int tpri; 7227c478bd9Sstevel@tonic-gate 723d4204c85Sraf for (prev = NULL; 724d4204c85Sraf (ulwp = *ulwpp) != NULL; 725d4204c85Sraf prev = ulwp, ulwpp = &ulwp->ul_link) { 726d4204c85Sraf if (ulwp->ul_stop) /* skip suspended threads */ 727d4204c85Sraf continue; 728d4204c85Sraf tpri = rt? CMP_PRIO(ulwp) : 0; 729d4204c85Sraf if (tpri > priority) { 730d4204c85Sraf foundpp = ulwpp; 731d4204c85Sraf *prevp = prev; 732d4204c85Sraf priority = tpri; 733d4204c85Sraf if (!rt) 734d4204c85Sraf break; 735d4204c85Sraf } 736d4204c85Sraf } 737d4204c85Sraf return (foundpp); 738d4204c85Sraf } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 741d4204c85Sraf * For real-time, we search the entire queue because the dispatch 742d4204c85Sraf * (kernel) priorities may have changed since enqueueing. 7437c478bd9Sstevel@tonic-gate */ 744d4204c85Sraf static ulwp_t ** 745d4204c85Sraf queue_slot_rt(ulwp_t **ulwpp_org, ulwp_t **prevp) 746d4204c85Sraf { 747d4204c85Sraf ulwp_t **ulwpp = ulwpp_org; 748d4204c85Sraf ulwp_t *ulwp = *ulwpp; 749d4204c85Sraf ulwp_t **foundpp = ulwpp; 750d4204c85Sraf int priority = CMP_PRIO(ulwp); 751d4204c85Sraf ulwp_t *prev; 752d4204c85Sraf int tpri; 753d4204c85Sraf 754d4204c85Sraf for (prev = ulwp, ulwpp = &ulwp->ul_link; 755d4204c85Sraf (ulwp = *ulwpp) != NULL; 7567c478bd9Sstevel@tonic-gate prev = ulwp, ulwpp = &ulwp->ul_link) { 757d4204c85Sraf tpri = CMP_PRIO(ulwp); 758d4204c85Sraf if (tpri > priority) { 759d4204c85Sraf foundpp = ulwpp; 760d4204c85Sraf *prevp = prev; 761d4204c85Sraf priority = tpri; 762d4204c85Sraf } 763d4204c85Sraf } 764d4204c85Sraf ulwp = *foundpp; 765d4204c85Sraf 7667c478bd9Sstevel@tonic-gate /* 7677c478bd9Sstevel@tonic-gate * Try not to return a suspended thread. 7687c478bd9Sstevel@tonic-gate * This mimics the old libthread's behavior. 7697c478bd9Sstevel@tonic-gate */ 770d4204c85Sraf if (ulwp->ul_stop && 771d4204c85Sraf (ulwpp = queue_slot_runnable(ulwpp_org, prevp, 1)) != NULL) { 772d4204c85Sraf foundpp = ulwpp; 773d4204c85Sraf ulwp = *foundpp; 7747c478bd9Sstevel@tonic-gate } 775d4204c85Sraf ulwp->ul_rt = 1; 776d4204c85Sraf return (foundpp); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate 779d4204c85Sraf ulwp_t ** 780d4204c85Sraf queue_slot(queue_head_t *qp, ulwp_t **prevp, int *more) 781d4204c85Sraf { 782d4204c85Sraf queue_root_t *qrp; 783d4204c85Sraf ulwp_t **ulwpp; 784d4204c85Sraf ulwp_t *ulwp; 785d4204c85Sraf int rt; 786d4204c85Sraf 787d4204c85Sraf ASSERT(MUTEX_OWNED(&qp->qh_lock, curthread)); 788d4204c85Sraf 789d4204c85Sraf if ((qrp = qp->qh_root) == NULL || (ulwp = qrp->qr_head) == NULL) { 7907c478bd9Sstevel@tonic-gate *more = 0; 791d4204c85Sraf return (NULL); /* no lwps on the queue */ 7927c478bd9Sstevel@tonic-gate } 793d4204c85Sraf rt = (qrp->qr_rtcount != 0); 794d4204c85Sraf *prevp = NULL; 795d4204c85Sraf if (ulwp->ul_link == NULL) { /* only one lwp on the queue */ 796d4204c85Sraf *more = 0; 797d4204c85Sraf ulwp->ul_rt = rt; 798d4204c85Sraf return (&qrp->qr_head); 799d4204c85Sraf } 800d4204c85Sraf *more = 1; 8017c478bd9Sstevel@tonic-gate 802d4204c85Sraf if (rt) /* real-time queue */ 803d4204c85Sraf return (queue_slot_rt(&qrp->qr_head, prevp)); 804d4204c85Sraf /* 805d4204c85Sraf * Try not to return a suspended thread. 806d4204c85Sraf * This mimics the old libthread's behavior. 807d4204c85Sraf */ 808d4204c85Sraf if (ulwp->ul_stop && 809d4204c85Sraf (ulwpp = queue_slot_runnable(&qrp->qr_head, prevp, 0)) != NULL) { 810d4204c85Sraf ulwp = *ulwpp; 811d4204c85Sraf ulwp->ul_rt = 0; 8127c478bd9Sstevel@tonic-gate return (ulwpp); 813d4204c85Sraf } 814d4204c85Sraf /* 815d4204c85Sraf * The common case; just pick the first thread on the queue. 816d4204c85Sraf */ 817d4204c85Sraf ulwp->ul_rt = 0; 818d4204c85Sraf return (&qrp->qr_head); 819d4204c85Sraf } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* 822d4204c85Sraf * Common code for unlinking an lwp from a user-level sleep queue. 8237c478bd9Sstevel@tonic-gate */ 824d4204c85Sraf void 82541efec22Sraf queue_unlink(queue_head_t *qp, ulwp_t **ulwpp, ulwp_t *prev) 8267c478bd9Sstevel@tonic-gate { 827d4204c85Sraf queue_root_t *qrp = qp->qh_root; 828d4204c85Sraf queue_root_t *nqrp; 829d4204c85Sraf ulwp_t *ulwp = *ulwpp; 830d4204c85Sraf ulwp_t *next; 8317c478bd9Sstevel@tonic-gate 832d4204c85Sraf ASSERT(MUTEX_OWNED(&qp->qh_lock, curthread)); 833d4204c85Sraf ASSERT(qp->qh_wchan != NULL && ulwp->ul_wchan == qp->qh_wchan); 834d4204c85Sraf 835d4204c85Sraf DECR(qp->qh_qlen); 836d4204c85Sraf DECR(qrp->qr_qlen); 837d4204c85Sraf if (ulwp->ul_rtqueued) { 838d4204c85Sraf ulwp->ul_rtqueued = 0; 839d4204c85Sraf qrp->qr_rtcount--; 840d4204c85Sraf } 841d4204c85Sraf next = ulwp->ul_link; 842d4204c85Sraf *ulwpp = next; 8437c478bd9Sstevel@tonic-gate ulwp->ul_link = NULL; 844d4204c85Sraf if (qrp->qr_tail == ulwp) 845d4204c85Sraf qrp->qr_tail = prev; 846d4204c85Sraf if (qrp == &ulwp->ul_queue_root) { 847d4204c85Sraf /* 848d4204c85Sraf * We can't continue to use the unlinked thread's 849d4204c85Sraf * queue root for the linkage. 850d4204c85Sraf */ 851d4204c85Sraf queue_root_t *qr_next = qrp->qr_next; 852d4204c85Sraf queue_root_t *qr_prev = qrp->qr_prev; 8537c478bd9Sstevel@tonic-gate 854d4204c85Sraf if (qrp->qr_tail) { 855d4204c85Sraf /* switch to using the last thread's queue root */ 856d4204c85Sraf ASSERT(qrp->qr_qlen != 0); 857d4204c85Sraf nqrp = &qrp->qr_tail->ul_queue_root; 858d4204c85Sraf *nqrp = *qrp; 859d4204c85Sraf if (qr_next) 860d4204c85Sraf qr_next->qr_prev = nqrp; 861d4204c85Sraf if (qr_prev) 862d4204c85Sraf qr_prev->qr_next = nqrp; 863d4204c85Sraf else 864d4204c85Sraf qp->qh_hlist = nqrp; 865d4204c85Sraf qp->qh_root = nqrp; 866d4204c85Sraf } else { 867d4204c85Sraf /* empty queue root; just delete from the hash list */ 868d4204c85Sraf ASSERT(qrp->qr_qlen == 0); 869d4204c85Sraf if (qr_next) 870d4204c85Sraf qr_next->qr_prev = qr_prev; 871d4204c85Sraf if (qr_prev) 872d4204c85Sraf qr_prev->qr_next = qr_next; 873d4204c85Sraf else 874d4204c85Sraf qp->qh_hlist = qr_next; 875d4204c85Sraf qp->qh_root = NULL; 876d4204c85Sraf DECR(qp->qh_hlen); 877d4204c85Sraf } 878d4204c85Sraf } 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 88141efec22Sraf ulwp_t * 882d4204c85Sraf dequeue(queue_head_t *qp, int *more) 88341efec22Sraf { 88441efec22Sraf ulwp_t **ulwpp; 885d4204c85Sraf ulwp_t *ulwp; 88641efec22Sraf ulwp_t *prev; 88741efec22Sraf 888d4204c85Sraf if ((ulwpp = queue_slot(qp, &prev, more)) == NULL) 88941efec22Sraf return (NULL); 890d4204c85Sraf ulwp = *ulwpp; 891d4204c85Sraf queue_unlink(qp, ulwpp, prev); 892d4204c85Sraf ulwp->ul_sleepq = NULL; 893d4204c85Sraf ulwp->ul_wchan = NULL; 894d4204c85Sraf return (ulwp); 89541efec22Sraf } 89641efec22Sraf 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * Return a pointer to the highest priority thread sleeping on wchan. 8997c478bd9Sstevel@tonic-gate */ 9007c478bd9Sstevel@tonic-gate ulwp_t * 901d4204c85Sraf queue_waiter(queue_head_t *qp) 9027c478bd9Sstevel@tonic-gate { 9037c478bd9Sstevel@tonic-gate ulwp_t **ulwpp; 904d4204c85Sraf ulwp_t *prev; 905d4204c85Sraf int more; 9067c478bd9Sstevel@tonic-gate 907d4204c85Sraf if ((ulwpp = queue_slot(qp, &prev, &more)) == NULL) 9087c478bd9Sstevel@tonic-gate return (NULL); 9097c478bd9Sstevel@tonic-gate return (*ulwpp); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 912d4204c85Sraf int 913d4204c85Sraf dequeue_self(queue_head_t *qp) 9147c478bd9Sstevel@tonic-gate { 9157c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 916d4204c85Sraf queue_root_t *qrp; 9177c478bd9Sstevel@tonic-gate ulwp_t **ulwpp; 9187c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 919d4204c85Sraf ulwp_t *prev; 9207c478bd9Sstevel@tonic-gate int found = 0; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate ASSERT(MUTEX_OWNED(&qp->qh_lock, self)); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* find self on the sleep queue */ 925d4204c85Sraf if ((qrp = qp->qh_root) != NULL) { 926d4204c85Sraf for (prev = NULL, ulwpp = &qrp->qr_head; 927d4204c85Sraf (ulwp = *ulwpp) != NULL; 9287c478bd9Sstevel@tonic-gate prev = ulwp, ulwpp = &ulwp->ul_link) { 9297c478bd9Sstevel@tonic-gate if (ulwp == self) { 930d4204c85Sraf queue_unlink(qp, ulwpp, prev); 9317c478bd9Sstevel@tonic-gate self->ul_cvmutex = NULL; 932d4204c85Sraf self->ul_sleepq = NULL; 933d4204c85Sraf self->ul_wchan = NULL; 9347c478bd9Sstevel@tonic-gate found = 1; 9357c478bd9Sstevel@tonic-gate break; 9367c478bd9Sstevel@tonic-gate } 937d4204c85Sraf } 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate if (!found) 9417c478bd9Sstevel@tonic-gate thr_panic("dequeue_self(): curthread not found on queue"); 9427c478bd9Sstevel@tonic-gate 943d4204c85Sraf return ((qrp = qp->qh_root) != NULL && qrp->qr_head != NULL); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * Called from call_user_handler() and _thrp_suspend() to take 9487c478bd9Sstevel@tonic-gate * ourself off of our sleep queue so we can grab locks. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate void 9517c478bd9Sstevel@tonic-gate unsleep_self(void) 9527c478bd9Sstevel@tonic-gate { 9537c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 9547c478bd9Sstevel@tonic-gate queue_head_t *qp; 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * Calling enter_critical()/exit_critical() here would lead 9587c478bd9Sstevel@tonic-gate * to recursion. Just manipulate self->ul_critical directly. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate self->ul_critical++; 9617c478bd9Sstevel@tonic-gate while (self->ul_sleepq != NULL) { 9627c478bd9Sstevel@tonic-gate qp = queue_lock(self->ul_wchan, self->ul_qtype); 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * We may have been moved from a CV queue to a 9657c478bd9Sstevel@tonic-gate * mutex queue while we were attempting queue_lock(). 9667c478bd9Sstevel@tonic-gate * If so, just loop around and try again. 9677c478bd9Sstevel@tonic-gate * dequeue_self() clears self->ul_sleepq. 9687c478bd9Sstevel@tonic-gate */ 969d4204c85Sraf if (qp == self->ul_sleepq) 970d4204c85Sraf (void) dequeue_self(qp); 9717c478bd9Sstevel@tonic-gate queue_unlock(qp); 9727c478bd9Sstevel@tonic-gate } 973d4204c85Sraf self->ul_writer = 0; 9747c478bd9Sstevel@tonic-gate self->ul_critical--; 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * Common code for calling the the ___lwp_mutex_timedlock() system call. 9797c478bd9Sstevel@tonic-gate * Returns with mutex_owner and mutex_ownerpid set correctly. 9807c478bd9Sstevel@tonic-gate */ 981883492d5Sraf static int 9827c478bd9Sstevel@tonic-gate mutex_lock_kernel(mutex_t *mp, timespec_t *tsp, tdb_mutex_stats_t *msp) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 9857c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 986883492d5Sraf int mtype = mp->mutex_type; 9877c478bd9Sstevel@tonic-gate hrtime_t begin_sleep; 988883492d5Sraf int acquired; 9897c478bd9Sstevel@tonic-gate int error; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate self->ul_sp = stkptr(); 9927c478bd9Sstevel@tonic-gate self->ul_wchan = mp; 9937c478bd9Sstevel@tonic-gate if (__td_event_report(self, TD_SLEEP, udp)) { 9947c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_SLEEP; 9957c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventdata = mp; 9967c478bd9Sstevel@tonic-gate tdb_event(TD_SLEEP, udp); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate if (msp) { 9997c478bd9Sstevel@tonic-gate tdb_incr(msp->mutex_sleep); 10007c478bd9Sstevel@tonic-gate begin_sleep = gethrtime(); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate DTRACE_PROBE1(plockstat, mutex__block, mp); 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate for (;;) { 1006883492d5Sraf /* 1007883492d5Sraf * A return value of EOWNERDEAD or ELOCKUNMAPPED 1008883492d5Sraf * means we successfully acquired the lock. 1009883492d5Sraf */ 1010db94676fSRoger A. Faulkner if ((error = ___lwp_mutex_timedlock(mp, tsp, self)) != 0 && 1011883492d5Sraf error != EOWNERDEAD && error != ELOCKUNMAPPED) { 1012883492d5Sraf acquired = 0; 10137c478bd9Sstevel@tonic-gate break; 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 1016883492d5Sraf if (mtype & USYNC_PROCESS) { 10177c478bd9Sstevel@tonic-gate /* 10187c478bd9Sstevel@tonic-gate * Defend against forkall(). We may be the child, 10197c478bd9Sstevel@tonic-gate * in which case we don't actually own the mutex. 10207c478bd9Sstevel@tonic-gate */ 10217c478bd9Sstevel@tonic-gate enter_critical(self); 10227c478bd9Sstevel@tonic-gate if (mp->mutex_ownerpid == udp->pid) { 10237c478bd9Sstevel@tonic-gate exit_critical(self); 1024883492d5Sraf acquired = 1; 10257c478bd9Sstevel@tonic-gate break; 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate exit_critical(self); 10287c478bd9Sstevel@tonic-gate } else { 1029883492d5Sraf acquired = 1; 10307c478bd9Sstevel@tonic-gate break; 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate } 1033328cc3e9SRoger A. Faulkner 10347c478bd9Sstevel@tonic-gate if (msp) 10357c478bd9Sstevel@tonic-gate msp->mutex_sleep_time += gethrtime() - begin_sleep; 10367c478bd9Sstevel@tonic-gate self->ul_wchan = NULL; 10377c478bd9Sstevel@tonic-gate self->ul_sp = 0; 10387c478bd9Sstevel@tonic-gate 1039883492d5Sraf if (acquired) { 1040db94676fSRoger A. Faulkner ASSERT(mp->mutex_owner == (uintptr_t)self); 1041883492d5Sraf DTRACE_PROBE2(plockstat, mutex__blocked, mp, 1); 1042883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 1043883492d5Sraf } else { 1044883492d5Sraf DTRACE_PROBE2(plockstat, mutex__blocked, mp, 0); 1045883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, error); 1046883492d5Sraf } 1047883492d5Sraf 10487c478bd9Sstevel@tonic-gate return (error); 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate /* 10527c478bd9Sstevel@tonic-gate * Common code for calling the ___lwp_mutex_trylock() system call. 10537c478bd9Sstevel@tonic-gate * Returns with mutex_owner and mutex_ownerpid set correctly. 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate int 10567c478bd9Sstevel@tonic-gate mutex_trylock_kernel(mutex_t *mp) 10577c478bd9Sstevel@tonic-gate { 10587c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 10597c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 1060883492d5Sraf int mtype = mp->mutex_type; 10617c478bd9Sstevel@tonic-gate int error; 1062883492d5Sraf int acquired; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate for (;;) { 1065883492d5Sraf /* 1066883492d5Sraf * A return value of EOWNERDEAD or ELOCKUNMAPPED 1067883492d5Sraf * means we successfully acquired the lock. 1068883492d5Sraf */ 1069db94676fSRoger A. Faulkner if ((error = ___lwp_mutex_trylock(mp, self)) != 0 && 1070883492d5Sraf error != EOWNERDEAD && error != ELOCKUNMAPPED) { 1071883492d5Sraf acquired = 0; 10727c478bd9Sstevel@tonic-gate break; 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 1075883492d5Sraf if (mtype & USYNC_PROCESS) { 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * Defend against forkall(). We may be the child, 10787c478bd9Sstevel@tonic-gate * in which case we don't actually own the mutex. 10797c478bd9Sstevel@tonic-gate */ 10807c478bd9Sstevel@tonic-gate enter_critical(self); 10817c478bd9Sstevel@tonic-gate if (mp->mutex_ownerpid == udp->pid) { 10827c478bd9Sstevel@tonic-gate exit_critical(self); 1083883492d5Sraf acquired = 1; 10847c478bd9Sstevel@tonic-gate break; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate exit_critical(self); 10877c478bd9Sstevel@tonic-gate } else { 1088883492d5Sraf acquired = 1; 10897c478bd9Sstevel@tonic-gate break; 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 1093883492d5Sraf if (acquired) { 1094db94676fSRoger A. Faulkner ASSERT(mp->mutex_owner == (uintptr_t)self); 1095883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 1096883492d5Sraf } else if (error != EBUSY) { 1097883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, error); 1098883492d5Sraf } 1099883492d5Sraf 11007c478bd9Sstevel@tonic-gate return (error); 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate volatile sc_shared_t * 11047c478bd9Sstevel@tonic-gate setup_schedctl(void) 11057c478bd9Sstevel@tonic-gate { 11067c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 11077c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp; 11087c478bd9Sstevel@tonic-gate sc_shared_t *tmp; 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate if ((scp = self->ul_schedctl) == NULL && /* no shared state yet */ 11117c478bd9Sstevel@tonic-gate !self->ul_vfork && /* not a child of vfork() */ 11127c478bd9Sstevel@tonic-gate !self->ul_schedctl_called) { /* haven't been called before */ 11137c478bd9Sstevel@tonic-gate enter_critical(self); 11147c478bd9Sstevel@tonic-gate self->ul_schedctl_called = &self->ul_uberdata->uberflags; 11157c478bd9Sstevel@tonic-gate if ((tmp = __schedctl()) != (sc_shared_t *)(-1)) 11167c478bd9Sstevel@tonic-gate self->ul_schedctl = scp = tmp; 11177c478bd9Sstevel@tonic-gate exit_critical(self); 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * Unless the call to setup_schedctl() is surrounded 11217c478bd9Sstevel@tonic-gate * by enter_critical()/exit_critical(), the address 11227c478bd9Sstevel@tonic-gate * we are returning could be invalid due to a forkall() 11237c478bd9Sstevel@tonic-gate * having occurred in another thread. 11247c478bd9Sstevel@tonic-gate */ 11257c478bd9Sstevel@tonic-gate return (scp); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * Interfaces from libsched, incorporated into libc. 11307c478bd9Sstevel@tonic-gate * libsched.so.1 is now a filter library onto libc. 11317c478bd9Sstevel@tonic-gate */ 11327257d1b4Sraf #pragma weak schedctl_lookup = schedctl_init 11337c478bd9Sstevel@tonic-gate schedctl_t * 11347257d1b4Sraf schedctl_init(void) 11357c478bd9Sstevel@tonic-gate { 11367c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp = setup_schedctl(); 11377c478bd9Sstevel@tonic-gate return ((scp == NULL)? NULL : (schedctl_t *)&scp->sc_preemptctl); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate void 11417257d1b4Sraf schedctl_exit(void) 11427c478bd9Sstevel@tonic-gate { 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * Contract private interface for java. 11477c478bd9Sstevel@tonic-gate * Set up the schedctl data if it doesn't exist yet. 11487c478bd9Sstevel@tonic-gate * Return a pointer to the pointer to the schedctl data. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate volatile sc_shared_t *volatile * 11517c478bd9Sstevel@tonic-gate _thr_schedctl(void) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 11547c478bd9Sstevel@tonic-gate volatile sc_shared_t *volatile *ptr; 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate if (self->ul_vfork) 11577c478bd9Sstevel@tonic-gate return (NULL); 11587c478bd9Sstevel@tonic-gate if (*(ptr = &self->ul_schedctl) == NULL) 11597c478bd9Sstevel@tonic-gate (void) setup_schedctl(); 11607c478bd9Sstevel@tonic-gate return (ptr); 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * Block signals and attempt to block preemption. 11657c478bd9Sstevel@tonic-gate * no_preempt()/preempt() must be used in pairs but can be nested. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate void 11687c478bd9Sstevel@tonic-gate no_preempt(ulwp_t *self) 11697c478bd9Sstevel@tonic-gate { 11707c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp; 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate if (self->ul_preempt++ == 0) { 11737c478bd9Sstevel@tonic-gate enter_critical(self); 11747c478bd9Sstevel@tonic-gate if ((scp = self->ul_schedctl) != NULL || 11757c478bd9Sstevel@tonic-gate (scp = setup_schedctl()) != NULL) { 11767c478bd9Sstevel@tonic-gate /* 11777c478bd9Sstevel@tonic-gate * Save the pre-existing preempt value. 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate self->ul_savpreempt = scp->sc_preemptctl.sc_nopreempt; 11807c478bd9Sstevel@tonic-gate scp->sc_preemptctl.sc_nopreempt = 1; 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate /* 11867c478bd9Sstevel@tonic-gate * Undo the effects of no_preempt(). 11877c478bd9Sstevel@tonic-gate */ 11887c478bd9Sstevel@tonic-gate void 11897c478bd9Sstevel@tonic-gate preempt(ulwp_t *self) 11907c478bd9Sstevel@tonic-gate { 11917c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate ASSERT(self->ul_preempt > 0); 11947c478bd9Sstevel@tonic-gate if (--self->ul_preempt == 0) { 11957c478bd9Sstevel@tonic-gate if ((scp = self->ul_schedctl) != NULL) { 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * Restore the pre-existing preempt value. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate scp->sc_preemptctl.sc_nopreempt = self->ul_savpreempt; 12007c478bd9Sstevel@tonic-gate if (scp->sc_preemptctl.sc_yield && 12017c478bd9Sstevel@tonic-gate scp->sc_preemptctl.sc_nopreempt == 0) { 12028cd45542Sraf yield(); 12037c478bd9Sstevel@tonic-gate if (scp->sc_preemptctl.sc_yield) { 12047c478bd9Sstevel@tonic-gate /* 12057c478bd9Sstevel@tonic-gate * Shouldn't happen. This is either 12067c478bd9Sstevel@tonic-gate * a race condition or the thread 12077c478bd9Sstevel@tonic-gate * just entered the real-time class. 12087c478bd9Sstevel@tonic-gate */ 12098cd45542Sraf yield(); 12107c478bd9Sstevel@tonic-gate scp->sc_preemptctl.sc_yield = 0; 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate exit_critical(self); 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate /* 12197c478bd9Sstevel@tonic-gate * If a call to preempt() would cause the current thread to yield or to 12207c478bd9Sstevel@tonic-gate * take deferred actions in exit_critical(), then unpark the specified 12217c478bd9Sstevel@tonic-gate * lwp so it can run while we delay. Return the original lwpid if the 12227c478bd9Sstevel@tonic-gate * unpark was not performed, else return zero. The tests are a repeat 12237c478bd9Sstevel@tonic-gate * of some of the tests in preempt(), above. This is a statistical 12247c478bd9Sstevel@tonic-gate * optimization solely for cond_sleep_queue(), below. 12257c478bd9Sstevel@tonic-gate */ 12267c478bd9Sstevel@tonic-gate static lwpid_t 12277c478bd9Sstevel@tonic-gate preempt_unpark(ulwp_t *self, lwpid_t lwpid) 12287c478bd9Sstevel@tonic-gate { 12297c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp = self->ul_schedctl; 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate ASSERT(self->ul_preempt == 1 && self->ul_critical > 0); 12327c478bd9Sstevel@tonic-gate if ((scp != NULL && scp->sc_preemptctl.sc_yield) || 12337c478bd9Sstevel@tonic-gate (self->ul_curplease && self->ul_critical == 1)) { 12347c478bd9Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 12357c478bd9Sstevel@tonic-gate lwpid = 0; 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate return (lwpid); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate /* 124116b01779Sraf * Spin for a while (if 'tryhard' is true), trying to grab the lock. 12427c478bd9Sstevel@tonic-gate * If this fails, return EBUSY and let the caller deal with it. 12437c478bd9Sstevel@tonic-gate * If this succeeds, return 0 with mutex_owner set to curthread. 12447c478bd9Sstevel@tonic-gate */ 1245883492d5Sraf static int 124616b01779Sraf mutex_trylock_adaptive(mutex_t *mp, int tryhard) 12477c478bd9Sstevel@tonic-gate { 12487c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 1249883492d5Sraf int error = EBUSY; 12507c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 12517c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp; 12525d1dd9a9Sraf volatile uint8_t *lockp = (volatile uint8_t *)&mp->mutex_lockw; 12535d1dd9a9Sraf volatile uint64_t *ownerp = (volatile uint64_t *)&mp->mutex_owner; 12545d1dd9a9Sraf uint32_t new_lockword; 12555d1dd9a9Sraf int count = 0; 12565d1dd9a9Sraf int max_count; 12575d1dd9a9Sraf uint8_t max_spinners; 12587c478bd9Sstevel@tonic-gate 1259883492d5Sraf ASSERT(!(mp->mutex_type & USYNC_PROCESS)); 12607c478bd9Sstevel@tonic-gate 1261328cc3e9SRoger A. Faulkner if (MUTEX_OWNED(mp, self)) 12627c478bd9Sstevel@tonic-gate return (EBUSY); 12637c478bd9Sstevel@tonic-gate 1264328cc3e9SRoger A. Faulkner enter_critical(self); 1265328cc3e9SRoger A. Faulkner 1266883492d5Sraf /* short-cut, not definitive (see below) */ 1267883492d5Sraf if (mp->mutex_flag & LOCK_NOTRECOVERABLE) { 1268883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 12695d1dd9a9Sraf error = ENOTRECOVERABLE; 12705d1dd9a9Sraf goto done; 1271883492d5Sraf } 1272883492d5Sraf 12735d1dd9a9Sraf /* 12745d1dd9a9Sraf * Make one attempt to acquire the lock before 12755d1dd9a9Sraf * incurring the overhead of the spin loop. 12765d1dd9a9Sraf */ 12775d1dd9a9Sraf if (set_lock_byte(lockp) == 0) { 12785d1dd9a9Sraf *ownerp = (uintptr_t)self; 12795d1dd9a9Sraf error = 0; 12805d1dd9a9Sraf goto done; 12815d1dd9a9Sraf } 12825d1dd9a9Sraf if (!tryhard) 12835d1dd9a9Sraf goto done; 12845d1dd9a9Sraf if (ncpus == 0) 12855d1dd9a9Sraf ncpus = (int)_sysconf(_SC_NPROCESSORS_ONLN); 12865d1dd9a9Sraf if ((max_spinners = self->ul_max_spinners) >= ncpus) 12875d1dd9a9Sraf max_spinners = ncpus - 1; 12885d1dd9a9Sraf max_count = (max_spinners != 0)? self->ul_adaptive_spin : 0; 12895d1dd9a9Sraf if (max_count == 0) 12905d1dd9a9Sraf goto done; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate /* 12937c478bd9Sstevel@tonic-gate * This spin loop is unfair to lwps that have already dropped into 12947c478bd9Sstevel@tonic-gate * the kernel to sleep. They will starve on a highly-contended mutex. 12957c478bd9Sstevel@tonic-gate * This is just too bad. The adaptive spin algorithm is intended 12967c478bd9Sstevel@tonic-gate * to allow programs with highly-contended locks (that is, broken 12977c478bd9Sstevel@tonic-gate * programs) to execute with reasonable speed despite their contention. 12987c478bd9Sstevel@tonic-gate * Being fair would reduce the speed of such programs and well-written 12997c478bd9Sstevel@tonic-gate * programs will not suffer in any case. 13007c478bd9Sstevel@tonic-gate */ 1301328cc3e9SRoger A. Faulkner if (spinners_incr(&mp->mutex_lockword, max_spinners) == -1) 13025d1dd9a9Sraf goto done; 13035d1dd9a9Sraf DTRACE_PROBE1(plockstat, mutex__spin, mp); 13045d1dd9a9Sraf for (count = 1; ; count++) { 13057c478bd9Sstevel@tonic-gate if (*lockp == 0 && set_lock_byte(lockp) == 0) { 13067c478bd9Sstevel@tonic-gate *ownerp = (uintptr_t)self; 1307883492d5Sraf error = 0; 1308883492d5Sraf break; 13097c478bd9Sstevel@tonic-gate } 13105d1dd9a9Sraf if (count == max_count) 13115d1dd9a9Sraf break; 13127c478bd9Sstevel@tonic-gate SMT_PAUSE(); 13137c478bd9Sstevel@tonic-gate /* 13147c478bd9Sstevel@tonic-gate * Stop spinning if the mutex owner is not running on 13157c478bd9Sstevel@tonic-gate * a processor; it will not drop the lock any time soon 13167c478bd9Sstevel@tonic-gate * and we would just be wasting time to keep spinning. 13177c478bd9Sstevel@tonic-gate * 13187c478bd9Sstevel@tonic-gate * Note that we are looking at another thread (ulwp_t) 13197c478bd9Sstevel@tonic-gate * without ensuring that the other thread does not exit. 13207c478bd9Sstevel@tonic-gate * The scheme relies on ulwp_t structures never being 13217c478bd9Sstevel@tonic-gate * deallocated by the library (the library employs a free 13227c478bd9Sstevel@tonic-gate * list of ulwp_t structs that are reused when new threads 13237c478bd9Sstevel@tonic-gate * are created) and on schedctl shared memory never being 13247c478bd9Sstevel@tonic-gate * deallocated once created via __schedctl(). 13257c478bd9Sstevel@tonic-gate * 13267c478bd9Sstevel@tonic-gate * Thus, the worst that can happen when the spinning thread 13277c478bd9Sstevel@tonic-gate * looks at the owner's schedctl data is that it is looking 13287c478bd9Sstevel@tonic-gate * at some other thread's schedctl data. This almost never 13297c478bd9Sstevel@tonic-gate * happens and is benign when it does. 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate if ((ulwp = (ulwp_t *)(uintptr_t)*ownerp) != NULL && 13327c478bd9Sstevel@tonic-gate ((scp = ulwp->ul_schedctl) == NULL || 13337c478bd9Sstevel@tonic-gate scp->sc_state != SC_ONPROC)) 13347c478bd9Sstevel@tonic-gate break; 13357c478bd9Sstevel@tonic-gate } 13365d1dd9a9Sraf new_lockword = spinners_decr(&mp->mutex_lockword); 13375d1dd9a9Sraf if (error && (new_lockword & (LOCKMASK | SPINNERMASK)) == 0) { 13385d1dd9a9Sraf /* 13395d1dd9a9Sraf * We haven't yet acquired the lock, the lock 13405d1dd9a9Sraf * is free, and there are no other spinners. 13415d1dd9a9Sraf * Make one final attempt to acquire the lock. 13425d1dd9a9Sraf * 13435d1dd9a9Sraf * This isn't strictly necessary since mutex_lock_queue() 13445d1dd9a9Sraf * (the next action this thread will take if it doesn't 13455d1dd9a9Sraf * acquire the lock here) makes one attempt to acquire 13465d1dd9a9Sraf * the lock before putting the thread to sleep. 13475d1dd9a9Sraf * 13485d1dd9a9Sraf * If the next action for this thread (on failure here) 13495d1dd9a9Sraf * were not to call mutex_lock_queue(), this would be 13505d1dd9a9Sraf * necessary for correctness, to avoid ending up with an 13515d1dd9a9Sraf * unheld mutex with waiters but no one to wake them up. 13525d1dd9a9Sraf */ 13535d1dd9a9Sraf if (set_lock_byte(lockp) == 0) { 13545d1dd9a9Sraf *ownerp = (uintptr_t)self; 13555d1dd9a9Sraf error = 0; 13565d1dd9a9Sraf } 13575d1dd9a9Sraf count++; 13585d1dd9a9Sraf } 13597c478bd9Sstevel@tonic-gate 13605d1dd9a9Sraf done: 1361883492d5Sraf if (error == 0 && (mp->mutex_flag & LOCK_NOTRECOVERABLE)) { 1362883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 1363883492d5Sraf /* 136431db3c26Sraf * We shouldn't own the mutex. 136531db3c26Sraf * Just clear the lock; everyone has already been waked up. 1366883492d5Sraf */ 1367328cc3e9SRoger A. Faulkner *ownerp = 0; 136831db3c26Sraf (void) clear_lockbyte(&mp->mutex_lockword); 1369883492d5Sraf error = ENOTRECOVERABLE; 1370883492d5Sraf } 13717c478bd9Sstevel@tonic-gate 1372328cc3e9SRoger A. Faulkner exit_critical(self); 1373328cc3e9SRoger A. Faulkner 1374883492d5Sraf if (error) { 13755d1dd9a9Sraf if (count) { 13768cb74972SJonathan Haslam DTRACE_PROBE3(plockstat, mutex__spun, mp, 0, count); 13775d1dd9a9Sraf } 1378883492d5Sraf if (error != EBUSY) { 1379883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, error); 1380883492d5Sraf } 1381883492d5Sraf } else { 13825d1dd9a9Sraf if (count) { 13838cb74972SJonathan Haslam DTRACE_PROBE3(plockstat, mutex__spun, mp, 1, count); 13845d1dd9a9Sraf } 1385883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, count); 1386883492d5Sraf if (mp->mutex_flag & LOCK_OWNERDEAD) { 1387883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 1388883492d5Sraf error = EOWNERDEAD; 1389883492d5Sraf } 1390883492d5Sraf } 1391883492d5Sraf 1392883492d5Sraf return (error); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate /* 13967c478bd9Sstevel@tonic-gate * Same as mutex_trylock_adaptive(), except specifically for queue locks. 13977c478bd9Sstevel@tonic-gate * The owner field is not set here; the caller (spin_lock_set()) sets it. 13987c478bd9Sstevel@tonic-gate */ 1399883492d5Sraf static int 14007c478bd9Sstevel@tonic-gate mutex_queuelock_adaptive(mutex_t *mp) 14017c478bd9Sstevel@tonic-gate { 14027c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 14037c478bd9Sstevel@tonic-gate volatile sc_shared_t *scp; 14047c478bd9Sstevel@tonic-gate volatile uint8_t *lockp; 14057c478bd9Sstevel@tonic-gate volatile uint64_t *ownerp; 14067c478bd9Sstevel@tonic-gate int count = curthread->ul_queue_spin; 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate ASSERT(mp->mutex_type == USYNC_THREAD); 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (count == 0) 14117c478bd9Sstevel@tonic-gate return (EBUSY); 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate lockp = (volatile uint8_t *)&mp->mutex_lockw; 14147c478bd9Sstevel@tonic-gate ownerp = (volatile uint64_t *)&mp->mutex_owner; 14157c478bd9Sstevel@tonic-gate while (--count >= 0) { 14167c478bd9Sstevel@tonic-gate if (*lockp == 0 && set_lock_byte(lockp) == 0) 14177c478bd9Sstevel@tonic-gate return (0); 14187c478bd9Sstevel@tonic-gate SMT_PAUSE(); 14197c478bd9Sstevel@tonic-gate if ((ulwp = (ulwp_t *)(uintptr_t)*ownerp) != NULL && 14207c478bd9Sstevel@tonic-gate ((scp = ulwp->ul_schedctl) == NULL || 14217c478bd9Sstevel@tonic-gate scp->sc_state != SC_ONPROC)) 14227c478bd9Sstevel@tonic-gate break; 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate return (EBUSY); 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate * Like mutex_trylock_adaptive(), but for process-shared mutexes. 143016b01779Sraf * Spin for a while (if 'tryhard' is true), trying to grab the lock. 14317c478bd9Sstevel@tonic-gate * If this fails, return EBUSY and let the caller deal with it. 14327c478bd9Sstevel@tonic-gate * If this succeeds, return 0 with mutex_owner set to curthread 14337c478bd9Sstevel@tonic-gate * and mutex_ownerpid set to the current pid. 14347c478bd9Sstevel@tonic-gate */ 1435883492d5Sraf static int 143616b01779Sraf mutex_trylock_process(mutex_t *mp, int tryhard) 14377c478bd9Sstevel@tonic-gate { 14387c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 14395d1dd9a9Sraf uberdata_t *udp = self->ul_uberdata; 1440883492d5Sraf int error = EBUSY; 144131db3c26Sraf volatile uint64_t *lockp = (volatile uint64_t *)&mp->mutex_lockword64; 14425d1dd9a9Sraf uint32_t new_lockword; 14435d1dd9a9Sraf int count = 0; 14445d1dd9a9Sraf int max_count; 14455d1dd9a9Sraf uint8_t max_spinners; 14467c478bd9Sstevel@tonic-gate 14477c5714f6Sraf #if defined(__sparc) && !defined(_LP64) 14487c5714f6Sraf /* horrible hack, necessary only on 32-bit sparc */ 14497c5714f6Sraf int fix_alignment_problem = 14507c5714f6Sraf (((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) && 14517c5714f6Sraf self->ul_misaligned && !(mp->mutex_type & LOCK_ROBUST)); 14527c5714f6Sraf #endif 14537c5714f6Sraf 1454883492d5Sraf ASSERT(mp->mutex_type & USYNC_PROCESS); 14557c478bd9Sstevel@tonic-gate 1456883492d5Sraf if (shared_mutex_held(mp)) 14577c478bd9Sstevel@tonic-gate return (EBUSY); 14587c478bd9Sstevel@tonic-gate 1459328cc3e9SRoger A. Faulkner enter_critical(self); 1460328cc3e9SRoger A. Faulkner 1461883492d5Sraf /* short-cut, not definitive (see below) */ 1462883492d5Sraf if (mp->mutex_flag & LOCK_NOTRECOVERABLE) { 1463883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 14645d1dd9a9Sraf error = ENOTRECOVERABLE; 14655d1dd9a9Sraf goto done; 1466883492d5Sraf } 1467883492d5Sraf 14685d1dd9a9Sraf /* 14695d1dd9a9Sraf * Make one attempt to acquire the lock before 14705d1dd9a9Sraf * incurring the overhead of the spin loop. 14715d1dd9a9Sraf */ 14727c5714f6Sraf #if defined(__sparc) && !defined(_LP64) 14737c5714f6Sraf /* horrible hack, necessary only on 32-bit sparc */ 14747c5714f6Sraf if (fix_alignment_problem) { 14757c5714f6Sraf if (set_lock_byte(&mp->mutex_lockw) == 0) { 14767c5714f6Sraf mp->mutex_ownerpid = udp->pid; 14777c5714f6Sraf mp->mutex_owner = (uintptr_t)self; 14787c5714f6Sraf error = 0; 14797c5714f6Sraf goto done; 14807c5714f6Sraf } 14817c5714f6Sraf } else 14827c5714f6Sraf #endif 148331db3c26Sraf if (set_lock_byte64(lockp, udp->pid) == 0) { 14845d1dd9a9Sraf mp->mutex_owner = (uintptr_t)self; 148531db3c26Sraf /* mp->mutex_ownerpid was set by set_lock_byte64() */ 14865d1dd9a9Sraf error = 0; 14875d1dd9a9Sraf goto done; 14885d1dd9a9Sraf } 14895d1dd9a9Sraf if (!tryhard) 14905d1dd9a9Sraf goto done; 1491883492d5Sraf if (ncpus == 0) 1492883492d5Sraf ncpus = (int)_sysconf(_SC_NPROCESSORS_ONLN); 14935d1dd9a9Sraf if ((max_spinners = self->ul_max_spinners) >= ncpus) 14945d1dd9a9Sraf max_spinners = ncpus - 1; 14955d1dd9a9Sraf max_count = (max_spinners != 0)? self->ul_adaptive_spin : 0; 14965d1dd9a9Sraf if (max_count == 0) 14975d1dd9a9Sraf goto done; 1498883492d5Sraf 14997c478bd9Sstevel@tonic-gate /* 15007c478bd9Sstevel@tonic-gate * This is a process-shared mutex. 15017c478bd9Sstevel@tonic-gate * We cannot know if the owner is running on a processor. 15027c478bd9Sstevel@tonic-gate * We just spin and hope that it is on a processor. 15037c478bd9Sstevel@tonic-gate */ 1504328cc3e9SRoger A. Faulkner if (spinners_incr(&mp->mutex_lockword, max_spinners) == -1) 15055d1dd9a9Sraf goto done; 15065d1dd9a9Sraf DTRACE_PROBE1(plockstat, mutex__spin, mp); 15075d1dd9a9Sraf for (count = 1; ; count++) { 15087c5714f6Sraf #if defined(__sparc) && !defined(_LP64) 15097c5714f6Sraf /* horrible hack, necessary only on 32-bit sparc */ 15107c5714f6Sraf if (fix_alignment_problem) { 15117c5714f6Sraf if ((*lockp & LOCKMASK64) == 0 && 15127c5714f6Sraf set_lock_byte(&mp->mutex_lockw) == 0) { 15137c5714f6Sraf mp->mutex_ownerpid = udp->pid; 15147c5714f6Sraf mp->mutex_owner = (uintptr_t)self; 15157c5714f6Sraf error = 0; 15167c5714f6Sraf break; 15177c5714f6Sraf } 15187c5714f6Sraf } else 15197c5714f6Sraf #endif 152031db3c26Sraf if ((*lockp & LOCKMASK64) == 0 && 152131db3c26Sraf set_lock_byte64(lockp, udp->pid) == 0) { 1522883492d5Sraf mp->mutex_owner = (uintptr_t)self; 152331db3c26Sraf /* mp->mutex_ownerpid was set by set_lock_byte64() */ 1524883492d5Sraf error = 0; 1525883492d5Sraf break; 15267c478bd9Sstevel@tonic-gate } 15275d1dd9a9Sraf if (count == max_count) 15285d1dd9a9Sraf break; 15297c478bd9Sstevel@tonic-gate SMT_PAUSE(); 15307c478bd9Sstevel@tonic-gate } 15315d1dd9a9Sraf new_lockword = spinners_decr(&mp->mutex_lockword); 15325d1dd9a9Sraf if (error && (new_lockword & (LOCKMASK | SPINNERMASK)) == 0) { 15335d1dd9a9Sraf /* 15345d1dd9a9Sraf * We haven't yet acquired the lock, the lock 15355d1dd9a9Sraf * is free, and there are no other spinners. 15365d1dd9a9Sraf * Make one final attempt to acquire the lock. 15375d1dd9a9Sraf * 15385d1dd9a9Sraf * This isn't strictly necessary since mutex_lock_kernel() 15395d1dd9a9Sraf * (the next action this thread will take if it doesn't 15405d1dd9a9Sraf * acquire the lock here) makes one attempt to acquire 15415d1dd9a9Sraf * the lock before putting the thread to sleep. 15425d1dd9a9Sraf * 15435d1dd9a9Sraf * If the next action for this thread (on failure here) 15445d1dd9a9Sraf * were not to call mutex_lock_kernel(), this would be 15455d1dd9a9Sraf * necessary for correctness, to avoid ending up with an 15465d1dd9a9Sraf * unheld mutex with waiters but no one to wake them up. 15475d1dd9a9Sraf */ 15487c5714f6Sraf #if defined(__sparc) && !defined(_LP64) 15497c5714f6Sraf /* horrible hack, necessary only on 32-bit sparc */ 15507c5714f6Sraf if (fix_alignment_problem) { 15517c5714f6Sraf if (set_lock_byte(&mp->mutex_lockw) == 0) { 15527c5714f6Sraf mp->mutex_ownerpid = udp->pid; 15537c5714f6Sraf mp->mutex_owner = (uintptr_t)self; 15547c5714f6Sraf error = 0; 15557c5714f6Sraf } 15567c5714f6Sraf } else 15577c5714f6Sraf #endif 155831db3c26Sraf if (set_lock_byte64(lockp, udp->pid) == 0) { 15595d1dd9a9Sraf mp->mutex_owner = (uintptr_t)self; 156031db3c26Sraf /* mp->mutex_ownerpid was set by set_lock_byte64() */ 15615d1dd9a9Sraf error = 0; 15625d1dd9a9Sraf } 15635d1dd9a9Sraf count++; 15645d1dd9a9Sraf } 1565883492d5Sraf 15665d1dd9a9Sraf done: 1567883492d5Sraf if (error == 0 && (mp->mutex_flag & LOCK_NOTRECOVERABLE)) { 1568883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 15697c478bd9Sstevel@tonic-gate /* 157031db3c26Sraf * We shouldn't own the mutex. 157131db3c26Sraf * Just clear the lock; everyone has already been waked up. 15727c478bd9Sstevel@tonic-gate */ 1573883492d5Sraf mp->mutex_owner = 0; 157431db3c26Sraf /* mp->mutex_ownerpid is cleared by clear_lockbyte64() */ 157531db3c26Sraf (void) clear_lockbyte64(&mp->mutex_lockword64); 1576883492d5Sraf error = ENOTRECOVERABLE; 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate 1579328cc3e9SRoger A. Faulkner exit_critical(self); 1580328cc3e9SRoger A. Faulkner 1581883492d5Sraf if (error) { 15825d1dd9a9Sraf if (count) { 15838cb74972SJonathan Haslam DTRACE_PROBE3(plockstat, mutex__spun, mp, 0, count); 15845d1dd9a9Sraf } 1585883492d5Sraf if (error != EBUSY) { 1586883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, error); 1587883492d5Sraf } 1588883492d5Sraf } else { 15895d1dd9a9Sraf if (count) { 15908cb74972SJonathan Haslam DTRACE_PROBE3(plockstat, mutex__spun, mp, 1, count); 15915d1dd9a9Sraf } 1592883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, count); 1593883492d5Sraf if (mp->mutex_flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) { 1594883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 1595883492d5Sraf if (mp->mutex_flag & LOCK_OWNERDEAD) 1596883492d5Sraf error = EOWNERDEAD; 1597883492d5Sraf else if (mp->mutex_type & USYNC_PROCESS_ROBUST) 1598883492d5Sraf error = ELOCKUNMAPPED; 1599883492d5Sraf else 1600883492d5Sraf error = EOWNERDEAD; 1601883492d5Sraf } 1602883492d5Sraf } 1603883492d5Sraf 1604883492d5Sraf return (error); 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate /* 16087c478bd9Sstevel@tonic-gate * Mutex wakeup code for releasing a USYNC_THREAD mutex. 16097c478bd9Sstevel@tonic-gate * Returns the lwpid of the thread that was dequeued, if any. 16107c478bd9Sstevel@tonic-gate * The caller of mutex_wakeup() must call __lwp_unpark(lwpid) 16117c478bd9Sstevel@tonic-gate * to wake up the specified lwp. 16127c478bd9Sstevel@tonic-gate */ 1613883492d5Sraf static lwpid_t 16147c478bd9Sstevel@tonic-gate mutex_wakeup(mutex_t *mp) 16157c478bd9Sstevel@tonic-gate { 16167c478bd9Sstevel@tonic-gate lwpid_t lwpid = 0; 1617d4204c85Sraf int more; 16187c478bd9Sstevel@tonic-gate queue_head_t *qp; 16197c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * Dequeue a waiter from the sleep queue. Don't touch the mutex 16237c478bd9Sstevel@tonic-gate * waiters bit if no one was found on the queue because the mutex 16247c478bd9Sstevel@tonic-gate * might have been deallocated or reallocated for another purpose. 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate qp = queue_lock(mp, MX); 1627d4204c85Sraf if ((ulwp = dequeue(qp, &more)) != NULL) { 16287c478bd9Sstevel@tonic-gate lwpid = ulwp->ul_lwpid; 1629d4204c85Sraf mp->mutex_waiters = more; 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate queue_unlock(qp); 16327c478bd9Sstevel@tonic-gate return (lwpid); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate /* 1636883492d5Sraf * Mutex wakeup code for releasing all waiters on a USYNC_THREAD mutex. 1637883492d5Sraf */ 1638883492d5Sraf static void 1639883492d5Sraf mutex_wakeup_all(mutex_t *mp) 1640883492d5Sraf { 1641883492d5Sraf queue_head_t *qp; 1642d4204c85Sraf queue_root_t *qrp; 1643883492d5Sraf int nlwpid = 0; 1644883492d5Sraf int maxlwps = MAXLWPS; 1645883492d5Sraf ulwp_t *ulwp; 1646883492d5Sraf lwpid_t buffer[MAXLWPS]; 1647883492d5Sraf lwpid_t *lwpid = buffer; 1648883492d5Sraf 1649883492d5Sraf /* 1650883492d5Sraf * Walk the list of waiters and prepare to wake up all of them. 1651883492d5Sraf * The waiters flag has already been cleared from the mutex. 1652883492d5Sraf * 1653883492d5Sraf * We keep track of lwpids that are to be unparked in lwpid[]. 1654883492d5Sraf * __lwp_unpark_all() is called to unpark all of them after 1655883492d5Sraf * they have been removed from the sleep queue and the sleep 1656883492d5Sraf * queue lock has been dropped. If we run out of space in our 1657883492d5Sraf * on-stack buffer, we need to allocate more but we can't call 1658883492d5Sraf * lmalloc() because we are holding a queue lock when the overflow 1659883492d5Sraf * occurs and lmalloc() acquires a lock. We can't use alloca() 1660883492d5Sraf * either because the application may have allocated a small 1661883492d5Sraf * stack and we don't want to overrun the stack. So we call 1662883492d5Sraf * alloc_lwpids() to allocate a bigger buffer using the mmap() 1663883492d5Sraf * system call directly since that path acquires no locks. 1664883492d5Sraf */ 1665883492d5Sraf qp = queue_lock(mp, MX); 1666d4204c85Sraf for (;;) { 1667d4204c85Sraf if ((qrp = qp->qh_root) == NULL || 1668d4204c85Sraf (ulwp = qrp->qr_head) == NULL) 1669d4204c85Sraf break; 1670d4204c85Sraf ASSERT(ulwp->ul_wchan == mp); 1671d4204c85Sraf queue_unlink(qp, &qrp->qr_head, NULL); 1672d4204c85Sraf ulwp->ul_sleepq = NULL; 1673d4204c85Sraf ulwp->ul_wchan = NULL; 1674883492d5Sraf if (nlwpid == maxlwps) 1675883492d5Sraf lwpid = alloc_lwpids(lwpid, &nlwpid, &maxlwps); 1676883492d5Sraf lwpid[nlwpid++] = ulwp->ul_lwpid; 1677883492d5Sraf } 1678883492d5Sraf 1679883492d5Sraf if (nlwpid == 0) { 1680883492d5Sraf queue_unlock(qp); 1681883492d5Sraf } else { 16825d1dd9a9Sraf mp->mutex_waiters = 0; 1683883492d5Sraf no_preempt(curthread); 1684883492d5Sraf queue_unlock(qp); 1685883492d5Sraf if (nlwpid == 1) 1686883492d5Sraf (void) __lwp_unpark(lwpid[0]); 1687883492d5Sraf else 1688883492d5Sraf (void) __lwp_unpark_all(lwpid, nlwpid); 1689883492d5Sraf preempt(curthread); 1690883492d5Sraf } 1691883492d5Sraf 1692883492d5Sraf if (lwpid != buffer) 16938cd45542Sraf (void) munmap((caddr_t)lwpid, maxlwps * sizeof (lwpid_t)); 1694883492d5Sraf } 1695883492d5Sraf 1696883492d5Sraf /* 16975d1dd9a9Sraf * Release a process-private mutex. 16985d1dd9a9Sraf * As an optimization, if there are waiters but there are also spinners 16995d1dd9a9Sraf * attempting to acquire the mutex, then don't bother waking up a waiter; 17005d1dd9a9Sraf * one of the spinners will acquire the mutex soon and it would be a waste 17015d1dd9a9Sraf * of resources to wake up some thread just to have it spin for a while 17025d1dd9a9Sraf * and then possibly go back to sleep. See mutex_trylock_adaptive(). 17037c478bd9Sstevel@tonic-gate */ 1704883492d5Sraf static lwpid_t 1705883492d5Sraf mutex_unlock_queue(mutex_t *mp, int release_all) 17067c478bd9Sstevel@tonic-gate { 1707328cc3e9SRoger A. Faulkner ulwp_t *self = curthread; 17085d1dd9a9Sraf lwpid_t lwpid = 0; 17095d1dd9a9Sraf uint32_t old_lockword; 17105d1dd9a9Sraf 17115d1dd9a9Sraf DTRACE_PROBE2(plockstat, mutex__release, mp, 0); 1712328cc3e9SRoger A. Faulkner sigoff(self); 171331db3c26Sraf mp->mutex_owner = 0; 17145d1dd9a9Sraf old_lockword = clear_lockbyte(&mp->mutex_lockword); 17155d1dd9a9Sraf if ((old_lockword & WAITERMASK) && 17165d1dd9a9Sraf (release_all || (old_lockword & SPINNERMASK) == 0)) { 17177c478bd9Sstevel@tonic-gate no_preempt(self); /* ensure a prompt wakeup */ 17185d1dd9a9Sraf if (release_all) 1719883492d5Sraf mutex_wakeup_all(mp); 17205d1dd9a9Sraf else 1721883492d5Sraf lwpid = mutex_wakeup(mp); 17227c478bd9Sstevel@tonic-gate if (lwpid == 0) 17237c478bd9Sstevel@tonic-gate preempt(self); 17245d1dd9a9Sraf } 1725328cc3e9SRoger A. Faulkner sigon(self); 17267c478bd9Sstevel@tonic-gate return (lwpid); 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate /* 17307c478bd9Sstevel@tonic-gate * Like mutex_unlock_queue(), but for process-shared mutexes. 17317c478bd9Sstevel@tonic-gate */ 1732883492d5Sraf static void 1733883492d5Sraf mutex_unlock_process(mutex_t *mp, int release_all) 17347c478bd9Sstevel@tonic-gate { 17357c5714f6Sraf ulwp_t *self = curthread; 173631db3c26Sraf uint64_t old_lockword64; 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 0); 1739328cc3e9SRoger A. Faulkner sigoff(self); 174031db3c26Sraf mp->mutex_owner = 0; 17417c5714f6Sraf #if defined(__sparc) && !defined(_LP64) 17427c5714f6Sraf /* horrible hack, necessary only on 32-bit sparc */ 17437c5714f6Sraf if (((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) && 17447c5714f6Sraf self->ul_misaligned && !(mp->mutex_type & LOCK_ROBUST)) { 17457c5714f6Sraf uint32_t old_lockword; 17467c5714f6Sraf mp->mutex_ownerpid = 0; 17477c5714f6Sraf old_lockword = clear_lockbyte(&mp->mutex_lockword); 17487c5714f6Sraf if ((old_lockword & WAITERMASK) && 17497c5714f6Sraf (release_all || (old_lockword & SPINNERMASK) == 0)) { 17507c5714f6Sraf no_preempt(self); /* ensure a prompt wakeup */ 17517c5714f6Sraf (void) ___lwp_mutex_wakeup(mp, release_all); 17527c5714f6Sraf preempt(self); 17537c5714f6Sraf } 1754328cc3e9SRoger A. Faulkner sigon(self); 17557c5714f6Sraf return; 17567c5714f6Sraf } 17577c5714f6Sraf #endif 175831db3c26Sraf /* mp->mutex_ownerpid is cleared by clear_lockbyte64() */ 175931db3c26Sraf old_lockword64 = clear_lockbyte64(&mp->mutex_lockword64); 176031db3c26Sraf if ((old_lockword64 & WAITERMASK64) && 176131db3c26Sraf (release_all || (old_lockword64 & SPINNERMASK64) == 0)) { 17625d1dd9a9Sraf no_preempt(self); /* ensure a prompt wakeup */ 1763883492d5Sraf (void) ___lwp_mutex_wakeup(mp, release_all); 17647c478bd9Sstevel@tonic-gate preempt(self); 17657c478bd9Sstevel@tonic-gate } 1766328cc3e9SRoger A. Faulkner sigon(self); 17675d1dd9a9Sraf } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate void 17707c478bd9Sstevel@tonic-gate stall(void) 17717c478bd9Sstevel@tonic-gate { 17727c478bd9Sstevel@tonic-gate for (;;) 17737c478bd9Sstevel@tonic-gate (void) mutex_lock_kernel(&stall_mutex, NULL, NULL); 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate /* 17777c478bd9Sstevel@tonic-gate * Acquire a USYNC_THREAD mutex via user-level sleep queues. 17787c478bd9Sstevel@tonic-gate * We failed set_lock_byte(&mp->mutex_lockw) before coming here. 1779883492d5Sraf * If successful, returns with mutex_owner set correctly. 17807c478bd9Sstevel@tonic-gate */ 17817c478bd9Sstevel@tonic-gate int 17827c478bd9Sstevel@tonic-gate mutex_lock_queue(ulwp_t *self, tdb_mutex_stats_t *msp, mutex_t *mp, 17837c478bd9Sstevel@tonic-gate timespec_t *tsp) 17847c478bd9Sstevel@tonic-gate { 17857c478bd9Sstevel@tonic-gate uberdata_t *udp = curthread->ul_uberdata; 17867c478bd9Sstevel@tonic-gate queue_head_t *qp; 17877c478bd9Sstevel@tonic-gate hrtime_t begin_sleep; 17887c478bd9Sstevel@tonic-gate int error = 0; 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate self->ul_sp = stkptr(); 17917c478bd9Sstevel@tonic-gate if (__td_event_report(self, TD_SLEEP, udp)) { 17927c478bd9Sstevel@tonic-gate self->ul_wchan = mp; 17937c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_SLEEP; 17947c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventdata = mp; 17957c478bd9Sstevel@tonic-gate tdb_event(TD_SLEEP, udp); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate if (msp) { 17987c478bd9Sstevel@tonic-gate tdb_incr(msp->mutex_sleep); 17997c478bd9Sstevel@tonic-gate begin_sleep = gethrtime(); 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate DTRACE_PROBE1(plockstat, mutex__block, mp); 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate /* 18057c478bd9Sstevel@tonic-gate * Put ourself on the sleep queue, and while we are 18067c478bd9Sstevel@tonic-gate * unable to grab the lock, go park in the kernel. 18077c478bd9Sstevel@tonic-gate * Take ourself off the sleep queue after we acquire the lock. 18087c478bd9Sstevel@tonic-gate * The waiter bit can be set/cleared only while holding the queue lock. 18097c478bd9Sstevel@tonic-gate */ 18107c478bd9Sstevel@tonic-gate qp = queue_lock(mp, MX); 1811d4204c85Sraf enqueue(qp, self, 0); 18127c478bd9Sstevel@tonic-gate mp->mutex_waiters = 1; 18137c478bd9Sstevel@tonic-gate for (;;) { 18147c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) == 0) { 18157c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 1816d4204c85Sraf mp->mutex_waiters = dequeue_self(qp); 18177c478bd9Sstevel@tonic-gate break; 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate set_parking_flag(self, 1); 18207c478bd9Sstevel@tonic-gate queue_unlock(qp); 18217c478bd9Sstevel@tonic-gate /* 18227c478bd9Sstevel@tonic-gate * __lwp_park() will return the residual time in tsp 18237c478bd9Sstevel@tonic-gate * if we are unparked before the timeout expires. 18247c478bd9Sstevel@tonic-gate */ 18255d1dd9a9Sraf error = __lwp_park(tsp, 0); 18267c478bd9Sstevel@tonic-gate set_parking_flag(self, 0); 18277c478bd9Sstevel@tonic-gate /* 18287c478bd9Sstevel@tonic-gate * We could have taken a signal or suspended ourself. 18297c478bd9Sstevel@tonic-gate * If we did, then we removed ourself from the queue. 18307c478bd9Sstevel@tonic-gate * Someone else may have removed us from the queue 18317c478bd9Sstevel@tonic-gate * as a consequence of mutex_unlock(). We may have 18327c478bd9Sstevel@tonic-gate * gotten a timeout from __lwp_park(). Or we may still 18337c478bd9Sstevel@tonic-gate * be on the queue and this is just a spurious wakeup. 18347c478bd9Sstevel@tonic-gate */ 18357c478bd9Sstevel@tonic-gate qp = queue_lock(mp, MX); 18367c478bd9Sstevel@tonic-gate if (self->ul_sleepq == NULL) { 18375d1dd9a9Sraf if (error) { 1838d4204c85Sraf mp->mutex_waiters = queue_waiter(qp)? 1 : 0; 18395d1dd9a9Sraf if (error != EINTR) 18407c478bd9Sstevel@tonic-gate break; 18415d1dd9a9Sraf error = 0; 18425d1dd9a9Sraf } 18437c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) == 0) { 18447c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 18457c478bd9Sstevel@tonic-gate break; 18467c478bd9Sstevel@tonic-gate } 1847d4204c85Sraf enqueue(qp, self, 0); 18487c478bd9Sstevel@tonic-gate mp->mutex_waiters = 1; 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate ASSERT(self->ul_sleepq == qp && 18517c478bd9Sstevel@tonic-gate self->ul_qtype == MX && 18527c478bd9Sstevel@tonic-gate self->ul_wchan == mp); 18537c478bd9Sstevel@tonic-gate if (error) { 18545d1dd9a9Sraf if (error != EINTR) { 1855d4204c85Sraf mp->mutex_waiters = dequeue_self(qp); 18567c478bd9Sstevel@tonic-gate break; 18577c478bd9Sstevel@tonic-gate } 18585d1dd9a9Sraf error = 0; 18595d1dd9a9Sraf } 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate ASSERT(self->ul_sleepq == NULL && self->ul_link == NULL && 18627c478bd9Sstevel@tonic-gate self->ul_wchan == NULL); 18637c478bd9Sstevel@tonic-gate self->ul_sp = 0; 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate ASSERT(error == 0 || error == EINVAL || error == ETIME); 1866883492d5Sraf 1867883492d5Sraf if (error == 0 && (mp->mutex_flag & LOCK_NOTRECOVERABLE)) { 1868883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 1869883492d5Sraf /* 187031db3c26Sraf * We shouldn't own the mutex. 187131db3c26Sraf * Just clear the lock; everyone has already been waked up. 1872883492d5Sraf */ 1873883492d5Sraf mp->mutex_owner = 0; 187431db3c26Sraf (void) clear_lockbyte(&mp->mutex_lockword); 1875883492d5Sraf error = ENOTRECOVERABLE; 1876883492d5Sraf } 1877883492d5Sraf 1878328cc3e9SRoger A. Faulkner queue_unlock(qp); 1879328cc3e9SRoger A. Faulkner 1880328cc3e9SRoger A. Faulkner if (msp) 1881328cc3e9SRoger A. Faulkner msp->mutex_sleep_time += gethrtime() - begin_sleep; 1882328cc3e9SRoger A. Faulkner 1883883492d5Sraf if (error) { 1884883492d5Sraf DTRACE_PROBE2(plockstat, mutex__blocked, mp, 0); 1885883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, error); 1886883492d5Sraf } else { 1887883492d5Sraf DTRACE_PROBE2(plockstat, mutex__blocked, mp, 1); 1888883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 1889883492d5Sraf if (mp->mutex_flag & LOCK_OWNERDEAD) { 1890883492d5Sraf ASSERT(mp->mutex_type & LOCK_ROBUST); 1891883492d5Sraf error = EOWNERDEAD; 1892883492d5Sraf } 1893883492d5Sraf } 1894883492d5Sraf 18957c478bd9Sstevel@tonic-gate return (error); 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 1898883492d5Sraf static int 1899883492d5Sraf mutex_recursion(mutex_t *mp, int mtype, int try) 1900883492d5Sraf { 19017257d1b4Sraf ASSERT(mutex_held(mp)); 1902883492d5Sraf ASSERT(mtype & (LOCK_RECURSIVE|LOCK_ERRORCHECK)); 1903883492d5Sraf ASSERT(try == MUTEX_TRY || try == MUTEX_LOCK); 1904883492d5Sraf 1905883492d5Sraf if (mtype & LOCK_RECURSIVE) { 1906883492d5Sraf if (mp->mutex_rcount == RECURSION_MAX) { 1907883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, EAGAIN); 1908883492d5Sraf return (EAGAIN); 1909883492d5Sraf } 1910883492d5Sraf mp->mutex_rcount++; 1911883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 1, 0); 1912883492d5Sraf return (0); 1913883492d5Sraf } 1914883492d5Sraf if (try == MUTEX_LOCK) { 1915883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, EDEADLK); 1916883492d5Sraf return (EDEADLK); 1917883492d5Sraf } 1918883492d5Sraf return (EBUSY); 1919883492d5Sraf } 1920883492d5Sraf 1921883492d5Sraf /* 1922883492d5Sraf * Register this USYNC_PROCESS|LOCK_ROBUST mutex with the kernel so 1923883492d5Sraf * it can apply LOCK_OWNERDEAD|LOCK_UNMAPPED if it becomes necessary. 1924883492d5Sraf * We use tdb_hash_lock here and in the synch object tracking code in 1925883492d5Sraf * the tdb_agent.c file. There is no conflict between these two usages. 1926883492d5Sraf */ 1927883492d5Sraf void 1928883492d5Sraf register_lock(mutex_t *mp) 1929883492d5Sraf { 1930883492d5Sraf uberdata_t *udp = curthread->ul_uberdata; 1931883492d5Sraf uint_t hash = LOCK_HASH(mp); 1932883492d5Sraf robust_t *rlp; 193309ce0d4aSRoger A. Faulkner robust_t *invalid; 1934883492d5Sraf robust_t **rlpp; 1935883492d5Sraf robust_t **table; 1936883492d5Sraf 1937883492d5Sraf if ((table = udp->robustlocks) == NULL) { 1938883492d5Sraf lmutex_lock(&udp->tdb_hash_lock); 1939883492d5Sraf if ((table = udp->robustlocks) == NULL) { 1940883492d5Sraf table = lmalloc(LOCKHASHSZ * sizeof (robust_t *)); 19417257d1b4Sraf membar_producer(); 1942883492d5Sraf udp->robustlocks = table; 1943883492d5Sraf } 1944883492d5Sraf lmutex_unlock(&udp->tdb_hash_lock); 1945883492d5Sraf } 19467257d1b4Sraf membar_consumer(); 1947883492d5Sraf 1948883492d5Sraf /* 1949883492d5Sraf * First search the registered table with no locks held. 1950883492d5Sraf * This is safe because the table never shrinks 1951883492d5Sraf * and we can only get a false negative. 1952883492d5Sraf */ 1953883492d5Sraf for (rlp = table[hash]; rlp != NULL; rlp = rlp->robust_next) { 1954883492d5Sraf if (rlp->robust_lock == mp) /* already registered */ 1955883492d5Sraf return; 1956883492d5Sraf } 1957883492d5Sraf 1958883492d5Sraf /* 1959883492d5Sraf * The lock was not found. 1960883492d5Sraf * Repeat the operation with tdb_hash_lock held. 1961883492d5Sraf */ 1962883492d5Sraf lmutex_lock(&udp->tdb_hash_lock); 1963883492d5Sraf 196409ce0d4aSRoger A. Faulkner invalid = NULL; 1965883492d5Sraf for (rlpp = &table[hash]; 1966883492d5Sraf (rlp = *rlpp) != NULL; 1967883492d5Sraf rlpp = &rlp->robust_next) { 1968883492d5Sraf if (rlp->robust_lock == mp) { /* already registered */ 1969883492d5Sraf lmutex_unlock(&udp->tdb_hash_lock); 1970883492d5Sraf return; 1971883492d5Sraf } 197209ce0d4aSRoger A. Faulkner /* remember the first invalid entry, if any */ 197309ce0d4aSRoger A. Faulkner if (rlp->robust_lock == INVALID_ADDR && invalid == NULL) 197409ce0d4aSRoger A. Faulkner invalid = rlp; 1975883492d5Sraf } 1976883492d5Sraf 1977883492d5Sraf /* 1978883492d5Sraf * The lock has never been registered. 197909ce0d4aSRoger A. Faulkner * Add it to the table and register it now. 1980883492d5Sraf */ 1981c242ec1bSRoger A. Faulkner if ((rlp = invalid) != NULL) { 198209ce0d4aSRoger A. Faulkner /* 198309ce0d4aSRoger A. Faulkner * Reuse the invalid entry we found above. 198409ce0d4aSRoger A. Faulkner * The linkages are still correct. 198509ce0d4aSRoger A. Faulkner */ 1986c242ec1bSRoger A. Faulkner rlp->robust_lock = mp; 198709ce0d4aSRoger A. Faulkner membar_producer(); 198809ce0d4aSRoger A. Faulkner } else { 198909ce0d4aSRoger A. Faulkner /* 199009ce0d4aSRoger A. Faulkner * Allocate a new entry and add it to 199109ce0d4aSRoger A. Faulkner * the hash table and to the global list. 199209ce0d4aSRoger A. Faulkner */ 1993883492d5Sraf rlp = lmalloc(sizeof (*rlp)); 1994883492d5Sraf rlp->robust_lock = mp; 199509ce0d4aSRoger A. Faulkner rlp->robust_next = NULL; 199609ce0d4aSRoger A. Faulkner rlp->robust_list = udp->robustlist; 199709ce0d4aSRoger A. Faulkner udp->robustlist = rlp; 19987257d1b4Sraf membar_producer(); 1999883492d5Sraf *rlpp = rlp; 200009ce0d4aSRoger A. Faulkner } 200109ce0d4aSRoger A. Faulkner 200209ce0d4aSRoger A. Faulkner lmutex_unlock(&udp->tdb_hash_lock); 200309ce0d4aSRoger A. Faulkner 2004c242ec1bSRoger A. Faulkner (void) ___lwp_mutex_register(mp, &rlp->robust_lock); 2005883492d5Sraf } 2006883492d5Sraf 2007883492d5Sraf /* 2008883492d5Sraf * This is called in the child of fork()/forkall() to start over 2009883492d5Sraf * with a clean slate. (Each process must register its own locks.) 2010883492d5Sraf * No locks are needed because all other threads are suspended or gone. 2011883492d5Sraf */ 2012883492d5Sraf void 2013c242ec1bSRoger A. Faulkner unregister_locks(void) 2014883492d5Sraf { 2015883492d5Sraf uberdata_t *udp = curthread->ul_uberdata; 2016883492d5Sraf robust_t **table; 2017883492d5Sraf robust_t *rlp; 2018883492d5Sraf robust_t *next; 2019883492d5Sraf 202009ce0d4aSRoger A. Faulkner /* 202109ce0d4aSRoger A. Faulkner * Do this first, before calling lfree(). 202209ce0d4aSRoger A. Faulkner */ 202309ce0d4aSRoger A. Faulkner table = udp->robustlocks; 202409ce0d4aSRoger A. Faulkner udp->robustlocks = NULL; 202509ce0d4aSRoger A. Faulkner rlp = udp->robustlist; 202609ce0d4aSRoger A. Faulkner udp->robustlist = NULL; 202709ce0d4aSRoger A. Faulkner 202809ce0d4aSRoger A. Faulkner /* 2029c242ec1bSRoger A. Faulkner * Do this by traversing the global list, not the hash table. 203009ce0d4aSRoger A. Faulkner */ 2031883492d5Sraf while (rlp != NULL) { 203209ce0d4aSRoger A. Faulkner next = rlp->robust_list; 2033883492d5Sraf lfree(rlp, sizeof (*rlp)); 2034883492d5Sraf rlp = next; 2035883492d5Sraf } 203609ce0d4aSRoger A. Faulkner if (table != NULL) 2037883492d5Sraf lfree(table, LOCKHASHSZ * sizeof (robust_t *)); 2038883492d5Sraf } 2039883492d5Sraf 20407c478bd9Sstevel@tonic-gate /* 20417c478bd9Sstevel@tonic-gate * Returns with mutex_owner set correctly. 20427c478bd9Sstevel@tonic-gate */ 2043d4204c85Sraf int 20447c478bd9Sstevel@tonic-gate mutex_lock_internal(mutex_t *mp, timespec_t *tsp, int try) 20457c478bd9Sstevel@tonic-gate { 20467c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 20477c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 20487c478bd9Sstevel@tonic-gate int mtype = mp->mutex_type; 20497c478bd9Sstevel@tonic-gate tdb_mutex_stats_t *msp = MUTEX_STATS(mp, udp); 20507c478bd9Sstevel@tonic-gate int error = 0; 2051d4204c85Sraf int noceil = try & MUTEX_NOCEIL; 2052883492d5Sraf uint8_t ceil; 2053883492d5Sraf int myprio; 20547c478bd9Sstevel@tonic-gate 2055d4204c85Sraf try &= ~MUTEX_NOCEIL; 20567c478bd9Sstevel@tonic-gate ASSERT(try == MUTEX_TRY || try == MUTEX_LOCK); 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate if (!self->ul_schedctl_called) 20597c478bd9Sstevel@tonic-gate (void) setup_schedctl(); 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate if (msp && try == MUTEX_TRY) 20627c478bd9Sstevel@tonic-gate tdb_incr(msp->mutex_try); 20637c478bd9Sstevel@tonic-gate 20647257d1b4Sraf if ((mtype & (LOCK_RECURSIVE|LOCK_ERRORCHECK)) && mutex_held(mp)) 2065883492d5Sraf return (mutex_recursion(mp, mtype, try)); 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate if (self->ul_error_detection && try == MUTEX_LOCK && 20687257d1b4Sraf tsp == NULL && mutex_held(mp)) 20697c478bd9Sstevel@tonic-gate lock_error(mp, "mutex_lock", NULL, NULL); 20707c478bd9Sstevel@tonic-gate 2071d4204c85Sraf if ((mtype & LOCK_PRIO_PROTECT) && noceil == 0) { 2072d4204c85Sraf update_sched(self); 2073d4204c85Sraf if (self->ul_cid != self->ul_rtclassid) { 2074d4204c85Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, EPERM); 2075d4204c85Sraf return (EPERM); 2076d4204c85Sraf } 20777c478bd9Sstevel@tonic-gate ceil = mp->mutex_ceiling; 2078d4204c85Sraf myprio = self->ul_epri? self->ul_epri : self->ul_pri; 20797c478bd9Sstevel@tonic-gate if (myprio > ceil) { 2080883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, EINVAL); 20817c478bd9Sstevel@tonic-gate return (EINVAL); 20827c478bd9Sstevel@tonic-gate } 20837c478bd9Sstevel@tonic-gate if ((error = _ceil_mylist_add(mp)) != 0) { 2084883492d5Sraf DTRACE_PROBE2(plockstat, mutex__error, mp, error); 20857c478bd9Sstevel@tonic-gate return (error); 20867c478bd9Sstevel@tonic-gate } 20877c478bd9Sstevel@tonic-gate if (myprio < ceil) 20887c478bd9Sstevel@tonic-gate _ceil_prio_inherit(ceil); 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate 2091883492d5Sraf if ((mtype & (USYNC_PROCESS | LOCK_ROBUST)) 2092883492d5Sraf == (USYNC_PROCESS | LOCK_ROBUST)) 2093883492d5Sraf register_lock(mp); 2094883492d5Sraf 2095883492d5Sraf if (mtype & LOCK_PRIO_INHERIT) { 20967c478bd9Sstevel@tonic-gate /* go straight to the kernel */ 20977c478bd9Sstevel@tonic-gate if (try == MUTEX_TRY) 20987c478bd9Sstevel@tonic-gate error = mutex_trylock_kernel(mp); 20997c478bd9Sstevel@tonic-gate else /* MUTEX_LOCK */ 21007c478bd9Sstevel@tonic-gate error = mutex_lock_kernel(mp, tsp, msp); 21017c478bd9Sstevel@tonic-gate /* 21027c478bd9Sstevel@tonic-gate * The kernel never sets or clears the lock byte 2103883492d5Sraf * for LOCK_PRIO_INHERIT mutexes. 2104883492d5Sraf * Set it here for consistency. 21057c478bd9Sstevel@tonic-gate */ 21067c478bd9Sstevel@tonic-gate switch (error) { 21077c478bd9Sstevel@tonic-gate case 0: 2108d4204c85Sraf self->ul_pilocks++; 21097c478bd9Sstevel@tonic-gate mp->mutex_lockw = LOCKSET; 21107c478bd9Sstevel@tonic-gate break; 21117c478bd9Sstevel@tonic-gate case EOWNERDEAD: 2112883492d5Sraf case ELOCKUNMAPPED: 2113d4204c85Sraf self->ul_pilocks++; 2114883492d5Sraf mp->mutex_lockw = LOCKSET; 21157c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2116883492d5Sraf case ENOTRECOVERABLE: 2117883492d5Sraf ASSERT(mtype & LOCK_ROBUST); 2118883492d5Sraf break; 21197c478bd9Sstevel@tonic-gate case EDEADLK: 2120f52756fbSRoger A. Faulkner if (try == MUTEX_TRY) { 21217c478bd9Sstevel@tonic-gate error = EBUSY; 2122f52756fbSRoger A. Faulkner } else if (tsp != NULL) { /* simulate a timeout */ 2123f52756fbSRoger A. Faulkner /* 2124f52756fbSRoger A. Faulkner * Note: mutex_timedlock() never returns EINTR. 2125f52756fbSRoger A. Faulkner */ 2126f52756fbSRoger A. Faulkner timespec_t ts = *tsp; 2127f52756fbSRoger A. Faulkner timespec_t rts; 2128f52756fbSRoger A. Faulkner 2129f52756fbSRoger A. Faulkner while (__nanosleep(&ts, &rts) == EINTR) 2130f52756fbSRoger A. Faulkner ts = rts; 2131f52756fbSRoger A. Faulkner error = ETIME; 2132f52756fbSRoger A. Faulkner } else { /* simulate a deadlock */ 2133f52756fbSRoger A. Faulkner stall(); 2134f52756fbSRoger A. Faulkner } 21357c478bd9Sstevel@tonic-gate break; 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate } else if (mtype & USYNC_PROCESS) { 213816b01779Sraf error = mutex_trylock_process(mp, try == MUTEX_LOCK); 2139883492d5Sraf if (error == EBUSY && try == MUTEX_LOCK) 21407c478bd9Sstevel@tonic-gate error = mutex_lock_kernel(mp, tsp, msp); 21417c478bd9Sstevel@tonic-gate } else { /* USYNC_THREAD */ 214216b01779Sraf error = mutex_trylock_adaptive(mp, try == MUTEX_LOCK); 2143883492d5Sraf if (error == EBUSY && try == MUTEX_LOCK) 21447c478bd9Sstevel@tonic-gate error = mutex_lock_queue(self, msp, mp, tsp); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate switch (error) { 2148883492d5Sraf case 0: 21497c478bd9Sstevel@tonic-gate case EOWNERDEAD: 21507c478bd9Sstevel@tonic-gate case ELOCKUNMAPPED: 2151883492d5Sraf if (mtype & LOCK_ROBUST) 2152883492d5Sraf remember_lock(mp); 21537c478bd9Sstevel@tonic-gate if (msp) 21547c478bd9Sstevel@tonic-gate record_begin_hold(msp); 21557c478bd9Sstevel@tonic-gate break; 21567c478bd9Sstevel@tonic-gate default: 2157d4204c85Sraf if ((mtype & LOCK_PRIO_PROTECT) && noceil == 0) { 2158883492d5Sraf (void) _ceil_mylist_del(mp); 2159883492d5Sraf if (myprio < ceil) 2160883492d5Sraf _ceil_prio_waive(); 2161883492d5Sraf } 21627c478bd9Sstevel@tonic-gate if (try == MUTEX_TRY) { 21637c478bd9Sstevel@tonic-gate if (msp) 21647c478bd9Sstevel@tonic-gate tdb_incr(msp->mutex_try_fail); 21657c478bd9Sstevel@tonic-gate if (__td_event_report(self, TD_LOCK_TRY, udp)) { 21667c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_LOCK_TRY; 21677c478bd9Sstevel@tonic-gate tdb_event(TD_LOCK_TRY, udp); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate break; 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate return (error); 21747c478bd9Sstevel@tonic-gate } 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate int 21777c478bd9Sstevel@tonic-gate fast_process_lock(mutex_t *mp, timespec_t *tsp, int mtype, int try) 21787c478bd9Sstevel@tonic-gate { 21797c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 21807c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate /* 21837c478bd9Sstevel@tonic-gate * We know that USYNC_PROCESS is set in mtype and that 21847c478bd9Sstevel@tonic-gate * zero, one, or both of the flags LOCK_RECURSIVE and 21857c478bd9Sstevel@tonic-gate * LOCK_ERRORCHECK are set, and that no other flags are set. 21867c478bd9Sstevel@tonic-gate */ 2187883492d5Sraf ASSERT((mtype & ~(USYNC_PROCESS|LOCK_RECURSIVE|LOCK_ERRORCHECK)) == 0); 21887c478bd9Sstevel@tonic-gate enter_critical(self); 21897c5714f6Sraf #if defined(__sparc) && !defined(_LP64) 21907c5714f6Sraf /* horrible hack, necessary only on 32-bit sparc */ 21917c5714f6Sraf if (((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) && 21927c5714f6Sraf self->ul_misaligned) { 21937c5714f6Sraf if (set_lock_byte(&mp->mutex_lockw) == 0) { 21947c5714f6Sraf mp->mutex_ownerpid = udp->pid; 21957c5714f6Sraf mp->mutex_owner = (uintptr_t)self; 21967c5714f6Sraf exit_critical(self); 21977c5714f6Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 21987c5714f6Sraf return (0); 21997c5714f6Sraf } 22007c5714f6Sraf } else 22017c5714f6Sraf #endif 220231db3c26Sraf if (set_lock_byte64(&mp->mutex_lockword64, udp->pid) == 0) { 22037c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 220431db3c26Sraf /* mp->mutex_ownerpid was set by set_lock_byte64() */ 22057c478bd9Sstevel@tonic-gate exit_critical(self); 22067c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 22077c478bd9Sstevel@tonic-gate return (0); 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate exit_critical(self); 22107c478bd9Sstevel@tonic-gate 2211883492d5Sraf if ((mtype & (LOCK_RECURSIVE|LOCK_ERRORCHECK)) && shared_mutex_held(mp)) 2212883492d5Sraf return (mutex_recursion(mp, mtype, try)); 22137c478bd9Sstevel@tonic-gate 221416b01779Sraf if (try == MUTEX_LOCK) { 221516b01779Sraf if (mutex_trylock_process(mp, 1) == 0) 22167c478bd9Sstevel@tonic-gate return (0); 22177c478bd9Sstevel@tonic-gate return (mutex_lock_kernel(mp, tsp, NULL)); 221816b01779Sraf } 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate if (__td_event_report(self, TD_LOCK_TRY, udp)) { 22217c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_LOCK_TRY; 22227c478bd9Sstevel@tonic-gate tdb_event(TD_LOCK_TRY, udp); 22237c478bd9Sstevel@tonic-gate } 22247c478bd9Sstevel@tonic-gate return (EBUSY); 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate static int 22287c478bd9Sstevel@tonic-gate mutex_lock_impl(mutex_t *mp, timespec_t *tsp) 22297c478bd9Sstevel@tonic-gate { 22307c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 2231d4204c85Sraf int mtype = mp->mutex_type; 22327c478bd9Sstevel@tonic-gate uberflags_t *gflags; 22337c478bd9Sstevel@tonic-gate 22347c5714f6Sraf if (((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) && 22357c5714f6Sraf self->ul_error_detection && self->ul_misaligned == 0) 22367c5714f6Sraf lock_error(mp, "mutex_lock", NULL, "mutex is misaligned"); 22377c5714f6Sraf 22387c478bd9Sstevel@tonic-gate /* 22397c478bd9Sstevel@tonic-gate * Optimize the case of USYNC_THREAD, including 22407c478bd9Sstevel@tonic-gate * the LOCK_RECURSIVE and LOCK_ERRORCHECK cases, 22417c478bd9Sstevel@tonic-gate * no error detection, no lock statistics, 22427c478bd9Sstevel@tonic-gate * and the process has only a single thread. 22437c478bd9Sstevel@tonic-gate * (Most likely a traditional single-threaded application.) 22447c478bd9Sstevel@tonic-gate */ 2245d4204c85Sraf if (((mtype & ~(LOCK_RECURSIVE|LOCK_ERRORCHECK)) | 2246d4204c85Sraf self->ul_uberdata->uberflags.uf_all) == 0) { 22477c478bd9Sstevel@tonic-gate /* 22487c478bd9Sstevel@tonic-gate * Only one thread exists so we don't need an atomic operation. 2249328cc3e9SRoger A. Faulkner * We do, however, need to protect against signals. 22507c478bd9Sstevel@tonic-gate */ 22517c478bd9Sstevel@tonic-gate if (mp->mutex_lockw == 0) { 2252328cc3e9SRoger A. Faulkner sigoff(self); 22537c478bd9Sstevel@tonic-gate mp->mutex_lockw = LOCKSET; 22547c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 2255328cc3e9SRoger A. Faulkner sigon(self); 22567c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 22577c478bd9Sstevel@tonic-gate return (0); 22587c478bd9Sstevel@tonic-gate } 2259883492d5Sraf if (mtype && MUTEX_OWNER(mp) == self) 2260883492d5Sraf return (mutex_recursion(mp, mtype, MUTEX_LOCK)); 22617c478bd9Sstevel@tonic-gate /* 22627c478bd9Sstevel@tonic-gate * We have reached a deadlock, probably because the 22637c478bd9Sstevel@tonic-gate * process is executing non-async-signal-safe code in 22647c478bd9Sstevel@tonic-gate * a signal handler and is attempting to acquire a lock 22657c478bd9Sstevel@tonic-gate * that it already owns. This is not surprising, given 22667c478bd9Sstevel@tonic-gate * bad programming practices over the years that has 22677c478bd9Sstevel@tonic-gate * resulted in applications calling printf() and such 22687c478bd9Sstevel@tonic-gate * in their signal handlers. Unless the user has told 22697c478bd9Sstevel@tonic-gate * us that the signal handlers are safe by setting: 22707c478bd9Sstevel@tonic-gate * export _THREAD_ASYNC_SAFE=1 22717c478bd9Sstevel@tonic-gate * we return EDEADLK rather than actually deadlocking. 22727c478bd9Sstevel@tonic-gate */ 22737c478bd9Sstevel@tonic-gate if (tsp == NULL && 22747c478bd9Sstevel@tonic-gate MUTEX_OWNER(mp) == self && !self->ul_async_safe) { 22757c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__error, mp, EDEADLK); 22767c478bd9Sstevel@tonic-gate return (EDEADLK); 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate } 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate /* 22817c478bd9Sstevel@tonic-gate * Optimize the common cases of USYNC_THREAD or USYNC_PROCESS, 22827c478bd9Sstevel@tonic-gate * no error detection, and no lock statistics. 22837c478bd9Sstevel@tonic-gate * Include LOCK_RECURSIVE and LOCK_ERRORCHECK cases. 22847c478bd9Sstevel@tonic-gate */ 22857c478bd9Sstevel@tonic-gate if ((gflags = self->ul_schedctl_called) != NULL && 22867c478bd9Sstevel@tonic-gate (gflags->uf_trs_ted | 22877c478bd9Sstevel@tonic-gate (mtype & ~(USYNC_PROCESS|LOCK_RECURSIVE|LOCK_ERRORCHECK))) == 0) { 22887c478bd9Sstevel@tonic-gate if (mtype & USYNC_PROCESS) 22897c478bd9Sstevel@tonic-gate return (fast_process_lock(mp, tsp, mtype, MUTEX_LOCK)); 2290328cc3e9SRoger A. Faulkner sigoff(self); 22917c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) == 0) { 22927c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 2293328cc3e9SRoger A. Faulkner sigon(self); 22947c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 22957c478bd9Sstevel@tonic-gate return (0); 22967c478bd9Sstevel@tonic-gate } 2297328cc3e9SRoger A. Faulkner sigon(self); 2298883492d5Sraf if (mtype && MUTEX_OWNER(mp) == self) 2299883492d5Sraf return (mutex_recursion(mp, mtype, MUTEX_LOCK)); 230016b01779Sraf if (mutex_trylock_adaptive(mp, 1) != 0) 2301883492d5Sraf return (mutex_lock_queue(self, NULL, mp, tsp)); 23027c478bd9Sstevel@tonic-gate return (0); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate /* else do it the long way */ 23067c478bd9Sstevel@tonic-gate return (mutex_lock_internal(mp, tsp, MUTEX_LOCK)); 23077c478bd9Sstevel@tonic-gate } 23087c478bd9Sstevel@tonic-gate 23097257d1b4Sraf #pragma weak pthread_mutex_lock = mutex_lock 23107257d1b4Sraf #pragma weak _mutex_lock = mutex_lock 23117c478bd9Sstevel@tonic-gate int 23127257d1b4Sraf mutex_lock(mutex_t *mp) 23137c478bd9Sstevel@tonic-gate { 23147c478bd9Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 23157c478bd9Sstevel@tonic-gate return (mutex_lock_impl(mp, NULL)); 23167c478bd9Sstevel@tonic-gate } 23177c478bd9Sstevel@tonic-gate 2318*0d045c0dSRobert Mustacchi void 2319*0d045c0dSRobert Mustacchi mutex_enter(mutex_t *mp) 2320*0d045c0dSRobert Mustacchi { 2321*0d045c0dSRobert Mustacchi int ret; 2322*0d045c0dSRobert Mustacchi int attr = mp->mutex_type & ALL_ATTRIBUTES; 2323*0d045c0dSRobert Mustacchi 2324*0d045c0dSRobert Mustacchi /* 2325*0d045c0dSRobert Mustacchi * Require LOCK_ERRORCHECK, accept LOCK_RECURSIVE. 2326*0d045c0dSRobert Mustacchi */ 2327*0d045c0dSRobert Mustacchi if (attr != LOCK_ERRORCHECK && 2328*0d045c0dSRobert Mustacchi attr != (LOCK_ERRORCHECK | LOCK_RECURSIVE)) { 2329*0d045c0dSRobert Mustacchi mutex_panic(mp, "mutex_enter: bad mutex type"); 2330*0d045c0dSRobert Mustacchi } 2331*0d045c0dSRobert Mustacchi ret = mutex_lock(mp); 2332*0d045c0dSRobert Mustacchi if (ret == EDEADLK) { 2333*0d045c0dSRobert Mustacchi mutex_panic(mp, "recursive mutex_enter"); 2334*0d045c0dSRobert Mustacchi } else if (ret == EAGAIN) { 2335*0d045c0dSRobert Mustacchi mutex_panic(mp, "excessive recursive mutex_enter"); 2336*0d045c0dSRobert Mustacchi } else if (ret != 0) { 2337*0d045c0dSRobert Mustacchi mutex_panic(mp, "unknown mutex_enter failure"); 2338*0d045c0dSRobert Mustacchi } 2339*0d045c0dSRobert Mustacchi } 2340*0d045c0dSRobert Mustacchi 23417c478bd9Sstevel@tonic-gate int 23427257d1b4Sraf pthread_mutex_timedlock(pthread_mutex_t *_RESTRICT_KYWD mp, 23437257d1b4Sraf const struct timespec *_RESTRICT_KYWD abstime) 23447c478bd9Sstevel@tonic-gate { 23457c478bd9Sstevel@tonic-gate timespec_t tslocal; 23467c478bd9Sstevel@tonic-gate int error; 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 23497c478bd9Sstevel@tonic-gate abstime_to_reltime(CLOCK_REALTIME, abstime, &tslocal); 23507257d1b4Sraf error = mutex_lock_impl((mutex_t *)mp, &tslocal); 23517c478bd9Sstevel@tonic-gate if (error == ETIME) 23527c478bd9Sstevel@tonic-gate error = ETIMEDOUT; 23537c478bd9Sstevel@tonic-gate return (error); 23547c478bd9Sstevel@tonic-gate } 23557c478bd9Sstevel@tonic-gate 23567c478bd9Sstevel@tonic-gate int 23577257d1b4Sraf pthread_mutex_reltimedlock_np(pthread_mutex_t *_RESTRICT_KYWD mp, 23587257d1b4Sraf const struct timespec *_RESTRICT_KYWD reltime) 23597c478bd9Sstevel@tonic-gate { 23607c478bd9Sstevel@tonic-gate timespec_t tslocal; 23617c478bd9Sstevel@tonic-gate int error; 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 23647c478bd9Sstevel@tonic-gate tslocal = *reltime; 23657257d1b4Sraf error = mutex_lock_impl((mutex_t *)mp, &tslocal); 23667c478bd9Sstevel@tonic-gate if (error == ETIME) 23677c478bd9Sstevel@tonic-gate error = ETIMEDOUT; 23687c478bd9Sstevel@tonic-gate return (error); 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate 23717257d1b4Sraf #pragma weak pthread_mutex_trylock = mutex_trylock 23727c478bd9Sstevel@tonic-gate int 23737257d1b4Sraf mutex_trylock(mutex_t *mp) 23747c478bd9Sstevel@tonic-gate { 23757c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 23767c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 2377d4204c85Sraf int mtype = mp->mutex_type; 23787c478bd9Sstevel@tonic-gate uberflags_t *gflags; 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 2381d4204c85Sraf 23827c478bd9Sstevel@tonic-gate /* 23837c478bd9Sstevel@tonic-gate * Optimize the case of USYNC_THREAD, including 23847c478bd9Sstevel@tonic-gate * the LOCK_RECURSIVE and LOCK_ERRORCHECK cases, 23857c478bd9Sstevel@tonic-gate * no error detection, no lock statistics, 23867c478bd9Sstevel@tonic-gate * and the process has only a single thread. 23877c478bd9Sstevel@tonic-gate * (Most likely a traditional single-threaded application.) 23887c478bd9Sstevel@tonic-gate */ 2389d4204c85Sraf if (((mtype & ~(LOCK_RECURSIVE|LOCK_ERRORCHECK)) | 23907c478bd9Sstevel@tonic-gate udp->uberflags.uf_all) == 0) { 23917c478bd9Sstevel@tonic-gate /* 23927c478bd9Sstevel@tonic-gate * Only one thread exists so we don't need an atomic operation. 2393328cc3e9SRoger A. Faulkner * We do, however, need to protect against signals. 23947c478bd9Sstevel@tonic-gate */ 23957c478bd9Sstevel@tonic-gate if (mp->mutex_lockw == 0) { 2396328cc3e9SRoger A. Faulkner sigoff(self); 23977c478bd9Sstevel@tonic-gate mp->mutex_lockw = LOCKSET; 23987c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 2399328cc3e9SRoger A. Faulkner sigon(self); 24007c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 24017c478bd9Sstevel@tonic-gate return (0); 24027c478bd9Sstevel@tonic-gate } 2403883492d5Sraf if (mtype && MUTEX_OWNER(mp) == self) 2404883492d5Sraf return (mutex_recursion(mp, mtype, MUTEX_TRY)); 24057c478bd9Sstevel@tonic-gate return (EBUSY); 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate /* 24097c478bd9Sstevel@tonic-gate * Optimize the common cases of USYNC_THREAD or USYNC_PROCESS, 24107c478bd9Sstevel@tonic-gate * no error detection, and no lock statistics. 24117c478bd9Sstevel@tonic-gate * Include LOCK_RECURSIVE and LOCK_ERRORCHECK cases. 24127c478bd9Sstevel@tonic-gate */ 24137c478bd9Sstevel@tonic-gate if ((gflags = self->ul_schedctl_called) != NULL && 24147c478bd9Sstevel@tonic-gate (gflags->uf_trs_ted | 24157c478bd9Sstevel@tonic-gate (mtype & ~(USYNC_PROCESS|LOCK_RECURSIVE|LOCK_ERRORCHECK))) == 0) { 24167c478bd9Sstevel@tonic-gate if (mtype & USYNC_PROCESS) 24177c478bd9Sstevel@tonic-gate return (fast_process_lock(mp, NULL, mtype, MUTEX_TRY)); 2418328cc3e9SRoger A. Faulkner sigoff(self); 24197c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) == 0) { 24207c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 2421328cc3e9SRoger A. Faulkner sigon(self); 24227c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 24237c478bd9Sstevel@tonic-gate return (0); 24247c478bd9Sstevel@tonic-gate } 2425328cc3e9SRoger A. Faulkner sigon(self); 2426883492d5Sraf if (mtype && MUTEX_OWNER(mp) == self) 2427883492d5Sraf return (mutex_recursion(mp, mtype, MUTEX_TRY)); 2428883492d5Sraf if (__td_event_report(self, TD_LOCK_TRY, udp)) { 2429883492d5Sraf self->ul_td_evbuf.eventnum = TD_LOCK_TRY; 2430883492d5Sraf tdb_event(TD_LOCK_TRY, udp); 2431883492d5Sraf } 2432883492d5Sraf return (EBUSY); 2433883492d5Sraf } 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate /* else do it the long way */ 24367c478bd9Sstevel@tonic-gate return (mutex_lock_internal(mp, NULL, MUTEX_TRY)); 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate 24397c478bd9Sstevel@tonic-gate int 2440883492d5Sraf mutex_unlock_internal(mutex_t *mp, int retain_robust_flags) 24417c478bd9Sstevel@tonic-gate { 24427c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 24437c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 24447c478bd9Sstevel@tonic-gate int mtype = mp->mutex_type; 24457c478bd9Sstevel@tonic-gate tdb_mutex_stats_t *msp; 2446883492d5Sraf int error = 0; 2447883492d5Sraf int release_all; 24487c478bd9Sstevel@tonic-gate lwpid_t lwpid; 24497c478bd9Sstevel@tonic-gate 245080d89c86SRoger A. Faulkner if ((mtype & (LOCK_ERRORCHECK | LOCK_ROBUST)) && 245180d89c86SRoger A. Faulkner !mutex_held(mp)) 24527c478bd9Sstevel@tonic-gate return (EPERM); 24537c478bd9Sstevel@tonic-gate 24547257d1b4Sraf if (self->ul_error_detection && !mutex_held(mp)) 24557c478bd9Sstevel@tonic-gate lock_error(mp, "mutex_unlock", NULL, NULL); 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate if ((mtype & LOCK_RECURSIVE) && mp->mutex_rcount != 0) { 24587c478bd9Sstevel@tonic-gate mp->mutex_rcount--; 24597c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 1); 24607c478bd9Sstevel@tonic-gate return (0); 24617c478bd9Sstevel@tonic-gate } 24627c478bd9Sstevel@tonic-gate 24637c478bd9Sstevel@tonic-gate if ((msp = MUTEX_STATS(mp, udp)) != NULL) 24647c478bd9Sstevel@tonic-gate (void) record_hold_time(msp); 24657c478bd9Sstevel@tonic-gate 2466883492d5Sraf if (!retain_robust_flags && !(mtype & LOCK_PRIO_INHERIT) && 2467883492d5Sraf (mp->mutex_flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED))) { 246880d89c86SRoger A. Faulkner ASSERT(mtype & LOCK_ROBUST); 2469883492d5Sraf mp->mutex_flag &= ~(LOCK_OWNERDEAD | LOCK_UNMAPPED); 2470883492d5Sraf mp->mutex_flag |= LOCK_NOTRECOVERABLE; 2471883492d5Sraf } 2472883492d5Sraf release_all = ((mp->mutex_flag & LOCK_NOTRECOVERABLE) != 0); 2473883492d5Sraf 2474883492d5Sraf if (mtype & LOCK_PRIO_INHERIT) { 24757c478bd9Sstevel@tonic-gate no_preempt(self); 24767c478bd9Sstevel@tonic-gate mp->mutex_owner = 0; 247731db3c26Sraf /* mp->mutex_ownerpid is cleared by ___lwp_mutex_unlock() */ 24787c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 0); 24797c478bd9Sstevel@tonic-gate mp->mutex_lockw = LOCKCLEAR; 2480d4204c85Sraf self->ul_pilocks--; 24817c478bd9Sstevel@tonic-gate error = ___lwp_mutex_unlock(mp); 24827c478bd9Sstevel@tonic-gate preempt(self); 24837c478bd9Sstevel@tonic-gate } else if (mtype & USYNC_PROCESS) { 2484883492d5Sraf mutex_unlock_process(mp, release_all); 24857c478bd9Sstevel@tonic-gate } else { /* USYNC_THREAD */ 2486883492d5Sraf if ((lwpid = mutex_unlock_queue(mp, release_all)) != 0) { 24877c478bd9Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 24887c478bd9Sstevel@tonic-gate preempt(self); 24897c478bd9Sstevel@tonic-gate } 24907c478bd9Sstevel@tonic-gate } 24917c478bd9Sstevel@tonic-gate 2492883492d5Sraf if (mtype & LOCK_ROBUST) 2493883492d5Sraf forget_lock(mp); 2494883492d5Sraf 2495883492d5Sraf if ((mtype & LOCK_PRIO_PROTECT) && _ceil_mylist_del(mp)) 2496883492d5Sraf _ceil_prio_waive(); 2497883492d5Sraf 24987c478bd9Sstevel@tonic-gate return (error); 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate 25017257d1b4Sraf #pragma weak pthread_mutex_unlock = mutex_unlock 25027257d1b4Sraf #pragma weak _mutex_unlock = mutex_unlock 25037c478bd9Sstevel@tonic-gate int 25047257d1b4Sraf mutex_unlock(mutex_t *mp) 25057c478bd9Sstevel@tonic-gate { 25067c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 2507d4204c85Sraf int mtype = mp->mutex_type; 25087c478bd9Sstevel@tonic-gate uberflags_t *gflags; 25097c478bd9Sstevel@tonic-gate lwpid_t lwpid; 25107c478bd9Sstevel@tonic-gate short el; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate /* 25137c478bd9Sstevel@tonic-gate * Optimize the case of USYNC_THREAD, including 25147c478bd9Sstevel@tonic-gate * the LOCK_RECURSIVE and LOCK_ERRORCHECK cases, 25157c478bd9Sstevel@tonic-gate * no error detection, no lock statistics, 25167c478bd9Sstevel@tonic-gate * and the process has only a single thread. 25177c478bd9Sstevel@tonic-gate * (Most likely a traditional single-threaded application.) 25187c478bd9Sstevel@tonic-gate */ 2519d4204c85Sraf if (((mtype & ~(LOCK_RECURSIVE|LOCK_ERRORCHECK)) | 2520d4204c85Sraf self->ul_uberdata->uberflags.uf_all) == 0) { 25217c478bd9Sstevel@tonic-gate if (mtype) { 25227c478bd9Sstevel@tonic-gate /* 25237c478bd9Sstevel@tonic-gate * At this point we know that one or both of the 25247c478bd9Sstevel@tonic-gate * flags LOCK_RECURSIVE or LOCK_ERRORCHECK is set. 25257c478bd9Sstevel@tonic-gate */ 25267c478bd9Sstevel@tonic-gate if ((mtype & LOCK_ERRORCHECK) && !MUTEX_OWNED(mp, self)) 25277c478bd9Sstevel@tonic-gate return (EPERM); 25287c478bd9Sstevel@tonic-gate if ((mtype & LOCK_RECURSIVE) && mp->mutex_rcount != 0) { 25297c478bd9Sstevel@tonic-gate mp->mutex_rcount--; 25307c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 1); 25317c478bd9Sstevel@tonic-gate return (0); 25327c478bd9Sstevel@tonic-gate } 25337c478bd9Sstevel@tonic-gate } 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * Only one thread exists so we don't need an atomic operation. 25367c478bd9Sstevel@tonic-gate * Also, there can be no waiters. 25377c478bd9Sstevel@tonic-gate */ 2538328cc3e9SRoger A. Faulkner sigoff(self); 25397c478bd9Sstevel@tonic-gate mp->mutex_owner = 0; 25407c478bd9Sstevel@tonic-gate mp->mutex_lockword = 0; 2541328cc3e9SRoger A. Faulkner sigon(self); 25427c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 0); 25437c478bd9Sstevel@tonic-gate return (0); 25447c478bd9Sstevel@tonic-gate } 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate /* 25477c478bd9Sstevel@tonic-gate * Optimize the common cases of USYNC_THREAD or USYNC_PROCESS, 25487c478bd9Sstevel@tonic-gate * no error detection, and no lock statistics. 25497c478bd9Sstevel@tonic-gate * Include LOCK_RECURSIVE and LOCK_ERRORCHECK cases. 25507c478bd9Sstevel@tonic-gate */ 25517c478bd9Sstevel@tonic-gate if ((gflags = self->ul_schedctl_called) != NULL) { 25527c478bd9Sstevel@tonic-gate if (((el = gflags->uf_trs_ted) | mtype) == 0) { 25537c478bd9Sstevel@tonic-gate fast_unlock: 25545d1dd9a9Sraf if ((lwpid = mutex_unlock_queue(mp, 0)) != 0) { 25557c478bd9Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 25567c478bd9Sstevel@tonic-gate preempt(self); 25577c478bd9Sstevel@tonic-gate } 25587c478bd9Sstevel@tonic-gate return (0); 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate if (el) /* error detection or lock statistics */ 25617c478bd9Sstevel@tonic-gate goto slow_unlock; 25627c478bd9Sstevel@tonic-gate if ((mtype & ~(LOCK_RECURSIVE|LOCK_ERRORCHECK)) == 0) { 25637c478bd9Sstevel@tonic-gate /* 25647c478bd9Sstevel@tonic-gate * At this point we know that one or both of the 25657c478bd9Sstevel@tonic-gate * flags LOCK_RECURSIVE or LOCK_ERRORCHECK is set. 25667c478bd9Sstevel@tonic-gate */ 25677c478bd9Sstevel@tonic-gate if ((mtype & LOCK_ERRORCHECK) && !MUTEX_OWNED(mp, self)) 25687c478bd9Sstevel@tonic-gate return (EPERM); 25697c478bd9Sstevel@tonic-gate if ((mtype & LOCK_RECURSIVE) && mp->mutex_rcount != 0) { 25707c478bd9Sstevel@tonic-gate mp->mutex_rcount--; 25717c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 1); 25727c478bd9Sstevel@tonic-gate return (0); 25737c478bd9Sstevel@tonic-gate } 25747c478bd9Sstevel@tonic-gate goto fast_unlock; 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate if ((mtype & 25777c478bd9Sstevel@tonic-gate ~(USYNC_PROCESS|LOCK_RECURSIVE|LOCK_ERRORCHECK)) == 0) { 25787c478bd9Sstevel@tonic-gate /* 25797c478bd9Sstevel@tonic-gate * At this point we know that zero, one, or both of the 25807c478bd9Sstevel@tonic-gate * flags LOCK_RECURSIVE or LOCK_ERRORCHECK is set and 25817c478bd9Sstevel@tonic-gate * that the USYNC_PROCESS flag is set. 25827c478bd9Sstevel@tonic-gate */ 25837c478bd9Sstevel@tonic-gate if ((mtype & LOCK_ERRORCHECK) && !shared_mutex_held(mp)) 25847c478bd9Sstevel@tonic-gate return (EPERM); 25857c478bd9Sstevel@tonic-gate if ((mtype & LOCK_RECURSIVE) && mp->mutex_rcount != 0) { 25867c478bd9Sstevel@tonic-gate mp->mutex_rcount--; 25877c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 1); 25887c478bd9Sstevel@tonic-gate return (0); 25897c478bd9Sstevel@tonic-gate } 2590883492d5Sraf mutex_unlock_process(mp, 0); 25917c478bd9Sstevel@tonic-gate return (0); 25927c478bd9Sstevel@tonic-gate } 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate /* else do it the long way */ 25967c478bd9Sstevel@tonic-gate slow_unlock: 2597883492d5Sraf return (mutex_unlock_internal(mp, 0)); 25987c478bd9Sstevel@tonic-gate } 25997c478bd9Sstevel@tonic-gate 2600*0d045c0dSRobert Mustacchi void 2601*0d045c0dSRobert Mustacchi mutex_exit(mutex_t *mp) 2602*0d045c0dSRobert Mustacchi { 2603*0d045c0dSRobert Mustacchi int ret; 2604*0d045c0dSRobert Mustacchi int attr = mp->mutex_type & ALL_ATTRIBUTES; 2605*0d045c0dSRobert Mustacchi 2606*0d045c0dSRobert Mustacchi if (attr != LOCK_ERRORCHECK && 2607*0d045c0dSRobert Mustacchi attr != (LOCK_ERRORCHECK | LOCK_RECURSIVE)) { 2608*0d045c0dSRobert Mustacchi mutex_panic(mp, "mutex_exit: bad mutex type"); 2609*0d045c0dSRobert Mustacchi } 2610*0d045c0dSRobert Mustacchi ret = mutex_unlock(mp); 2611*0d045c0dSRobert Mustacchi if (ret == EPERM) { 2612*0d045c0dSRobert Mustacchi mutex_panic(mp, "mutex_exit: not owner"); 2613*0d045c0dSRobert Mustacchi } else if (ret != 0) { 2614*0d045c0dSRobert Mustacchi mutex_panic(mp, "unknown mutex_exit failure"); 2615*0d045c0dSRobert Mustacchi } 2616*0d045c0dSRobert Mustacchi 2617*0d045c0dSRobert Mustacchi } 2618*0d045c0dSRobert Mustacchi 26197c478bd9Sstevel@tonic-gate /* 26207c478bd9Sstevel@tonic-gate * Internally to the library, almost all mutex lock/unlock actions 26217c478bd9Sstevel@tonic-gate * go through these lmutex_ functions, to protect critical regions. 26227257d1b4Sraf * We replicate a bit of code from mutex_lock() and mutex_unlock() 26237c478bd9Sstevel@tonic-gate * to make these functions faster since we know that the mutex type 26247c478bd9Sstevel@tonic-gate * of all internal locks is USYNC_THREAD. We also know that internal 26257c478bd9Sstevel@tonic-gate * locking can never fail, so we panic if it does. 26267c478bd9Sstevel@tonic-gate */ 26277c478bd9Sstevel@tonic-gate void 26287c478bd9Sstevel@tonic-gate lmutex_lock(mutex_t *mp) 26297c478bd9Sstevel@tonic-gate { 26307c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 26317c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate ASSERT(mp->mutex_type == USYNC_THREAD); 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate enter_critical(self); 26367c478bd9Sstevel@tonic-gate /* 26377c478bd9Sstevel@tonic-gate * Optimize the case of no lock statistics and only a single thread. 26387c478bd9Sstevel@tonic-gate * (Most likely a traditional single-threaded application.) 26397c478bd9Sstevel@tonic-gate */ 26407c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_all == 0) { 26417c478bd9Sstevel@tonic-gate /* 26427c478bd9Sstevel@tonic-gate * Only one thread exists; the mutex must be free. 26437c478bd9Sstevel@tonic-gate */ 26447c478bd9Sstevel@tonic-gate ASSERT(mp->mutex_lockw == 0); 26457c478bd9Sstevel@tonic-gate mp->mutex_lockw = LOCKSET; 26467c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 26477c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 26487c478bd9Sstevel@tonic-gate } else { 26497c478bd9Sstevel@tonic-gate tdb_mutex_stats_t *msp = MUTEX_STATS(mp, udp); 26507c478bd9Sstevel@tonic-gate 26517c478bd9Sstevel@tonic-gate if (!self->ul_schedctl_called) 26527c478bd9Sstevel@tonic-gate (void) setup_schedctl(); 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) == 0) { 26557c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 26567c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 265716b01779Sraf } else if (mutex_trylock_adaptive(mp, 1) != 0) { 26587c478bd9Sstevel@tonic-gate (void) mutex_lock_queue(self, msp, mp, NULL); 26597c478bd9Sstevel@tonic-gate } 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate if (msp) 26627c478bd9Sstevel@tonic-gate record_begin_hold(msp); 26637c478bd9Sstevel@tonic-gate } 26647c478bd9Sstevel@tonic-gate } 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate void 26677c478bd9Sstevel@tonic-gate lmutex_unlock(mutex_t *mp) 26687c478bd9Sstevel@tonic-gate { 26697c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 26707c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 26717c478bd9Sstevel@tonic-gate 26727c478bd9Sstevel@tonic-gate ASSERT(mp->mutex_type == USYNC_THREAD); 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate /* 26757c478bd9Sstevel@tonic-gate * Optimize the case of no lock statistics and only a single thread. 26767c478bd9Sstevel@tonic-gate * (Most likely a traditional single-threaded application.) 26777c478bd9Sstevel@tonic-gate */ 26787c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_all == 0) { 26797c478bd9Sstevel@tonic-gate /* 26807c478bd9Sstevel@tonic-gate * Only one thread exists so there can be no waiters. 26817c478bd9Sstevel@tonic-gate */ 26827c478bd9Sstevel@tonic-gate mp->mutex_owner = 0; 26837c478bd9Sstevel@tonic-gate mp->mutex_lockword = 0; 26847c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 0); 26857c478bd9Sstevel@tonic-gate } else { 26867c478bd9Sstevel@tonic-gate tdb_mutex_stats_t *msp = MUTEX_STATS(mp, udp); 26877c478bd9Sstevel@tonic-gate lwpid_t lwpid; 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate if (msp) 26907c478bd9Sstevel@tonic-gate (void) record_hold_time(msp); 2691883492d5Sraf if ((lwpid = mutex_unlock_queue(mp, 0)) != 0) { 26927c478bd9Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 26937c478bd9Sstevel@tonic-gate preempt(self); 26947c478bd9Sstevel@tonic-gate } 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate exit_critical(self); 26977c478bd9Sstevel@tonic-gate } 26987c478bd9Sstevel@tonic-gate 2699f841f6adSraf /* 2700f841f6adSraf * For specialized code in libc, like the asynchronous i/o code, 2701f841f6adSraf * the following sig_*() locking primitives are used in order 2702f841f6adSraf * to make the code asynchronous signal safe. Signals are 2703f841f6adSraf * deferred while locks acquired by these functions are held. 2704f841f6adSraf */ 2705f841f6adSraf void 2706f841f6adSraf sig_mutex_lock(mutex_t *mp) 2707f841f6adSraf { 2708e54ab87fSRoger A. Faulkner ulwp_t *self = curthread; 2709e54ab87fSRoger A. Faulkner 2710e54ab87fSRoger A. Faulkner sigoff(self); 27118cd45542Sraf (void) mutex_lock(mp); 2712f841f6adSraf } 2713f841f6adSraf 2714f841f6adSraf void 2715f841f6adSraf sig_mutex_unlock(mutex_t *mp) 2716f841f6adSraf { 2717e54ab87fSRoger A. Faulkner ulwp_t *self = curthread; 2718e54ab87fSRoger A. Faulkner 27198cd45542Sraf (void) mutex_unlock(mp); 2720e54ab87fSRoger A. Faulkner sigon(self); 2721f841f6adSraf } 2722f841f6adSraf 2723f841f6adSraf int 2724f841f6adSraf sig_mutex_trylock(mutex_t *mp) 2725f841f6adSraf { 2726e54ab87fSRoger A. Faulkner ulwp_t *self = curthread; 2727f841f6adSraf int error; 2728f841f6adSraf 2729e54ab87fSRoger A. Faulkner sigoff(self); 27308cd45542Sraf if ((error = mutex_trylock(mp)) != 0) 2731e54ab87fSRoger A. Faulkner sigon(self); 2732f841f6adSraf return (error); 2733f841f6adSraf } 2734f841f6adSraf 2735f841f6adSraf /* 2736f841f6adSraf * sig_cond_wait() is a cancellation point. 2737f841f6adSraf */ 2738f841f6adSraf int 2739f841f6adSraf sig_cond_wait(cond_t *cv, mutex_t *mp) 2740f841f6adSraf { 2741f841f6adSraf int error; 2742f841f6adSraf 2743f841f6adSraf ASSERT(curthread->ul_sigdefer != 0); 27448cd45542Sraf pthread_testcancel(); 2745a574db85Sraf error = __cond_wait(cv, mp); 2746f841f6adSraf if (error == EINTR && curthread->ul_cursig) { 2747f841f6adSraf sig_mutex_unlock(mp); 2748f841f6adSraf /* take the deferred signal here */ 2749f841f6adSraf sig_mutex_lock(mp); 2750f841f6adSraf } 27518cd45542Sraf pthread_testcancel(); 2752f841f6adSraf return (error); 2753f841f6adSraf } 2754f841f6adSraf 2755f841f6adSraf /* 2756f841f6adSraf * sig_cond_reltimedwait() is a cancellation point. 2757f841f6adSraf */ 2758f841f6adSraf int 2759f841f6adSraf sig_cond_reltimedwait(cond_t *cv, mutex_t *mp, const timespec_t *ts) 2760f841f6adSraf { 2761f841f6adSraf int error; 2762f841f6adSraf 2763f841f6adSraf ASSERT(curthread->ul_sigdefer != 0); 27648cd45542Sraf pthread_testcancel(); 2765a574db85Sraf error = __cond_reltimedwait(cv, mp, ts); 2766f841f6adSraf if (error == EINTR && curthread->ul_cursig) { 2767f841f6adSraf sig_mutex_unlock(mp); 2768f841f6adSraf /* take the deferred signal here */ 2769f841f6adSraf sig_mutex_lock(mp); 2770f841f6adSraf } 27718cd45542Sraf pthread_testcancel(); 2772f841f6adSraf return (error); 2773f841f6adSraf } 2774f841f6adSraf 2775a574db85Sraf /* 2776a574db85Sraf * For specialized code in libc, like the stdio code. 2777a574db85Sraf * the following cancel_safe_*() locking primitives are used in 2778a574db85Sraf * order to make the code cancellation-safe. Cancellation is 2779a574db85Sraf * deferred while locks acquired by these functions are held. 2780a574db85Sraf */ 2781a574db85Sraf void 2782a574db85Sraf cancel_safe_mutex_lock(mutex_t *mp) 2783a574db85Sraf { 27848cd45542Sraf (void) mutex_lock(mp); 2785a574db85Sraf curthread->ul_libc_locks++; 2786a574db85Sraf } 2787a574db85Sraf 2788a574db85Sraf int 2789a574db85Sraf cancel_safe_mutex_trylock(mutex_t *mp) 2790a574db85Sraf { 2791a574db85Sraf int error; 2792a574db85Sraf 27938cd45542Sraf if ((error = mutex_trylock(mp)) == 0) 2794a574db85Sraf curthread->ul_libc_locks++; 2795a574db85Sraf return (error); 2796a574db85Sraf } 2797a574db85Sraf 2798a574db85Sraf void 2799a574db85Sraf cancel_safe_mutex_unlock(mutex_t *mp) 2800a574db85Sraf { 2801a574db85Sraf ulwp_t *self = curthread; 2802a574db85Sraf 2803a574db85Sraf ASSERT(self->ul_libc_locks != 0); 2804a574db85Sraf 28058cd45542Sraf (void) mutex_unlock(mp); 2806a574db85Sraf 2807a574db85Sraf /* 2808a574db85Sraf * Decrement the count of locks held by cancel_safe_mutex_lock(). 2809a574db85Sraf * If we are then in a position to terminate cleanly and 2810a574db85Sraf * if there is a pending cancellation and cancellation 2811a574db85Sraf * is not disabled and we received EINTR from a recent 2812a574db85Sraf * system call then perform the cancellation action now. 2813a574db85Sraf */ 2814a574db85Sraf if (--self->ul_libc_locks == 0 && 2815a574db85Sraf !(self->ul_vfork | self->ul_nocancel | 2816a574db85Sraf self->ul_critical | self->ul_sigdefer) && 2817a574db85Sraf cancel_active()) 28187257d1b4Sraf pthread_exit(PTHREAD_CANCELED); 2819a574db85Sraf } 2820a574db85Sraf 28217c478bd9Sstevel@tonic-gate static int 28227c478bd9Sstevel@tonic-gate shared_mutex_held(mutex_t *mparg) 28237c478bd9Sstevel@tonic-gate { 28247c478bd9Sstevel@tonic-gate /* 2825883492d5Sraf * The 'volatile' is necessary to make sure the compiler doesn't 2826883492d5Sraf * reorder the tests of the various components of the mutex. 2827883492d5Sraf * They must be tested in this order: 2828883492d5Sraf * mutex_lockw 2829883492d5Sraf * mutex_owner 2830883492d5Sraf * mutex_ownerpid 2831883492d5Sraf * This relies on the fact that everywhere mutex_lockw is cleared, 2832883492d5Sraf * mutex_owner and mutex_ownerpid are cleared before mutex_lockw 2833883492d5Sraf * is cleared, and that everywhere mutex_lockw is set, mutex_owner 2834883492d5Sraf * and mutex_ownerpid are set after mutex_lockw is set, and that 2835883492d5Sraf * mutex_lockw is set or cleared with a memory barrier. 28367c478bd9Sstevel@tonic-gate */ 28377c478bd9Sstevel@tonic-gate volatile mutex_t *mp = (volatile mutex_t *)mparg; 28387c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 28397c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 28407c478bd9Sstevel@tonic-gate 2841883492d5Sraf return (MUTEX_OWNED(mp, self) && mp->mutex_ownerpid == udp->pid); 28427c478bd9Sstevel@tonic-gate } 28437c478bd9Sstevel@tonic-gate 28447257d1b4Sraf #pragma weak _mutex_held = mutex_held 28457c478bd9Sstevel@tonic-gate int 28467257d1b4Sraf mutex_held(mutex_t *mparg) 28477c478bd9Sstevel@tonic-gate { 2848883492d5Sraf volatile mutex_t *mp = (volatile mutex_t *)mparg; 2849883492d5Sraf 2850883492d5Sraf if (mparg->mutex_type & USYNC_PROCESS) 2851883492d5Sraf return (shared_mutex_held(mparg)); 28527c478bd9Sstevel@tonic-gate return (MUTEX_OWNED(mp, curthread)); 28537c478bd9Sstevel@tonic-gate } 28547c478bd9Sstevel@tonic-gate 28557257d1b4Sraf #pragma weak pthread_mutex_destroy = mutex_destroy 28567257d1b4Sraf #pragma weak _mutex_destroy = mutex_destroy 28577c478bd9Sstevel@tonic-gate int 28587257d1b4Sraf mutex_destroy(mutex_t *mp) 28597c478bd9Sstevel@tonic-gate { 2860883492d5Sraf if (mp->mutex_type & USYNC_PROCESS) 2861883492d5Sraf forget_lock(mp); 28628cd45542Sraf (void) memset(mp, 0, sizeof (*mp)); 28637c478bd9Sstevel@tonic-gate tdb_sync_obj_deregister(mp); 28647c478bd9Sstevel@tonic-gate return (0); 28657c478bd9Sstevel@tonic-gate } 28667c478bd9Sstevel@tonic-gate 28677257d1b4Sraf #pragma weak pthread_mutex_consistent_np = mutex_consistent 286880d89c86SRoger A. Faulkner #pragma weak pthread_mutex_consistent = mutex_consistent 2869883492d5Sraf int 28707257d1b4Sraf mutex_consistent(mutex_t *mp) 2871883492d5Sraf { 2872883492d5Sraf /* 2873883492d5Sraf * Do this only for an inconsistent, initialized robust lock 2874883492d5Sraf * that we hold. For all other cases, return EINVAL. 2875883492d5Sraf */ 28767257d1b4Sraf if (mutex_held(mp) && 2877883492d5Sraf (mp->mutex_type & LOCK_ROBUST) && 2878883492d5Sraf (mp->mutex_flag & LOCK_INITED) && 2879883492d5Sraf (mp->mutex_flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED))) { 2880883492d5Sraf mp->mutex_flag &= ~(LOCK_OWNERDEAD | LOCK_UNMAPPED); 2881883492d5Sraf mp->mutex_rcount = 0; 2882883492d5Sraf return (0); 2883883492d5Sraf } 2884883492d5Sraf return (EINVAL); 2885883492d5Sraf } 2886883492d5Sraf 28877c478bd9Sstevel@tonic-gate /* 28887c478bd9Sstevel@tonic-gate * Spin locks are separate from ordinary mutexes, 28897c478bd9Sstevel@tonic-gate * but we use the same data structure for them. 28907c478bd9Sstevel@tonic-gate */ 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate int 28937257d1b4Sraf pthread_spin_init(pthread_spinlock_t *lock, int pshared) 28947c478bd9Sstevel@tonic-gate { 28957c478bd9Sstevel@tonic-gate mutex_t *mp = (mutex_t *)lock; 28967c478bd9Sstevel@tonic-gate 28978cd45542Sraf (void) memset(mp, 0, sizeof (*mp)); 28987c478bd9Sstevel@tonic-gate if (pshared == PTHREAD_PROCESS_SHARED) 28997c478bd9Sstevel@tonic-gate mp->mutex_type = USYNC_PROCESS; 29007c478bd9Sstevel@tonic-gate else 29017c478bd9Sstevel@tonic-gate mp->mutex_type = USYNC_THREAD; 29027c478bd9Sstevel@tonic-gate mp->mutex_flag = LOCK_INITED; 29037c478bd9Sstevel@tonic-gate mp->mutex_magic = MUTEX_MAGIC; 29047c5714f6Sraf 29057c5714f6Sraf /* 29067c5714f6Sraf * This should be at the beginning of the function, 29077c5714f6Sraf * but for the sake of old broken applications that 29087c5714f6Sraf * do not have proper alignment for their mutexes 29097c5714f6Sraf * (and don't check the return code from pthread_spin_init), 29107c5714f6Sraf * we put it here, after initializing the mutex regardless. 29117c5714f6Sraf */ 29127c5714f6Sraf if (((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) && 29137c5714f6Sraf curthread->ul_misaligned == 0) 29147c5714f6Sraf return (EINVAL); 29157c5714f6Sraf 29167c478bd9Sstevel@tonic-gate return (0); 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate 29197c478bd9Sstevel@tonic-gate int 29207257d1b4Sraf pthread_spin_destroy(pthread_spinlock_t *lock) 29217c478bd9Sstevel@tonic-gate { 29228cd45542Sraf (void) memset(lock, 0, sizeof (*lock)); 29237c478bd9Sstevel@tonic-gate return (0); 29247c478bd9Sstevel@tonic-gate } 29257c478bd9Sstevel@tonic-gate 29267c478bd9Sstevel@tonic-gate int 29277257d1b4Sraf pthread_spin_trylock(pthread_spinlock_t *lock) 29287c478bd9Sstevel@tonic-gate { 29297c478bd9Sstevel@tonic-gate mutex_t *mp = (mutex_t *)lock; 29307c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 29317c478bd9Sstevel@tonic-gate int error = 0; 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate no_preempt(self); 29347c478bd9Sstevel@tonic-gate if (set_lock_byte(&mp->mutex_lockw) != 0) 29357c478bd9Sstevel@tonic-gate error = EBUSY; 29367c478bd9Sstevel@tonic-gate else { 29377c478bd9Sstevel@tonic-gate mp->mutex_owner = (uintptr_t)self; 29387c478bd9Sstevel@tonic-gate if (mp->mutex_type == USYNC_PROCESS) 29397c478bd9Sstevel@tonic-gate mp->mutex_ownerpid = self->ul_uberdata->pid; 29407c478bd9Sstevel@tonic-gate DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, 0); 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate preempt(self); 29437c478bd9Sstevel@tonic-gate return (error); 29447c478bd9Sstevel@tonic-gate } 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate int 29477257d1b4Sraf pthread_spin_lock(pthread_spinlock_t *lock) 29487c478bd9Sstevel@tonic-gate { 2949883492d5Sraf mutex_t *mp = (mutex_t *)lock; 2950883492d5Sraf ulwp_t *self = curthread; 2951883492d5Sraf volatile uint8_t *lockp = (volatile uint8_t *)&mp->mutex_lockw; 2952883492d5Sraf int count = 0; 29537c478bd9Sstevel@tonic-gate 2954883492d5Sraf ASSERT(!self->ul_critical || self->ul_bindflags); 2955883492d5Sraf 2956883492d5Sraf DTRACE_PROBE1(plockstat, mutex__spin, mp); 2957883492d5Sraf 29587c478bd9Sstevel@tonic-gate /* 29597c478bd9Sstevel@tonic-gate * We don't care whether the owner is running on a processor. 29607c478bd9Sstevel@tonic-gate * We just spin because that's what this interface requires. 29617c478bd9Sstevel@tonic-gate */ 29627c478bd9Sstevel@tonic-gate for (;;) { 29637c478bd9Sstevel@tonic-gate if (*lockp == 0) { /* lock byte appears to be clear */ 2964883492d5Sraf no_preempt(self); 2965883492d5Sraf if (set_lock_byte(lockp) == 0) 2966883492d5Sraf break; 2967883492d5Sraf preempt(self); 29687c478bd9Sstevel@tonic-gate } 29695d1dd9a9Sraf if (count < INT_MAX) 29705d1dd9a9Sraf count++; 29717c478bd9Sstevel@tonic-gate SMT_PAUSE(); 29727c478bd9Sstevel@tonic-gate } 2973883492d5Sraf mp->mutex_owner = (uintptr_t)self; 2974883492d5Sraf if (mp->mutex_type == USYNC_PROCESS) 2975883492d5Sraf mp->mutex_ownerpid = self->ul_uberdata->pid; 2976883492d5Sraf preempt(self); 29775d1dd9a9Sraf if (count) { 29788cb74972SJonathan Haslam DTRACE_PROBE3(plockstat, mutex__spun, mp, 1, count); 29795d1dd9a9Sraf } 2980883492d5Sraf DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, count); 2981883492d5Sraf return (0); 29827c478bd9Sstevel@tonic-gate } 29837c478bd9Sstevel@tonic-gate 29847c478bd9Sstevel@tonic-gate int 29857257d1b4Sraf pthread_spin_unlock(pthread_spinlock_t *lock) 29867c478bd9Sstevel@tonic-gate { 29877c478bd9Sstevel@tonic-gate mutex_t *mp = (mutex_t *)lock; 29887c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 29897c478bd9Sstevel@tonic-gate 29907c478bd9Sstevel@tonic-gate no_preempt(self); 29917c478bd9Sstevel@tonic-gate mp->mutex_owner = 0; 29927c478bd9Sstevel@tonic-gate mp->mutex_ownerpid = 0; 29937c478bd9Sstevel@tonic-gate DTRACE_PROBE2(plockstat, mutex__release, mp, 0); 299441efec22Sraf (void) atomic_swap_32(&mp->mutex_lockword, 0); 29957c478bd9Sstevel@tonic-gate preempt(self); 29967c478bd9Sstevel@tonic-gate return (0); 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate 29995d1dd9a9Sraf #define INITIAL_LOCKS 8 /* initial size of ul_heldlocks.array */ 3000883492d5Sraf 3001883492d5Sraf /* 3002883492d5Sraf * Find/allocate an entry for 'lock' in our array of held locks. 3003883492d5Sraf */ 3004883492d5Sraf static mutex_t ** 3005883492d5Sraf find_lock_entry(mutex_t *lock) 3006883492d5Sraf { 3007883492d5Sraf ulwp_t *self = curthread; 3008883492d5Sraf mutex_t **remembered = NULL; 3009883492d5Sraf mutex_t **lockptr; 3010883492d5Sraf uint_t nlocks; 3011883492d5Sraf 3012883492d5Sraf if ((nlocks = self->ul_heldlockcnt) != 0) 3013883492d5Sraf lockptr = self->ul_heldlocks.array; 3014883492d5Sraf else { 3015883492d5Sraf nlocks = 1; 3016883492d5Sraf lockptr = &self->ul_heldlocks.single; 3017883492d5Sraf } 3018883492d5Sraf 3019883492d5Sraf for (; nlocks; nlocks--, lockptr++) { 3020883492d5Sraf if (*lockptr == lock) 3021883492d5Sraf return (lockptr); 3022883492d5Sraf if (*lockptr == NULL && remembered == NULL) 3023883492d5Sraf remembered = lockptr; 3024883492d5Sraf } 3025883492d5Sraf if (remembered != NULL) { 3026883492d5Sraf *remembered = lock; 3027883492d5Sraf return (remembered); 3028883492d5Sraf } 3029883492d5Sraf 3030883492d5Sraf /* 3031883492d5Sraf * No entry available. Allocate more space, converting 3032883492d5Sraf * the single entry into an array of entries if necessary. 3033883492d5Sraf */ 3034883492d5Sraf if ((nlocks = self->ul_heldlockcnt) == 0) { 3035883492d5Sraf /* 3036883492d5Sraf * Initial allocation of the array. 3037883492d5Sraf * Convert the single entry into an array. 3038883492d5Sraf */ 3039883492d5Sraf self->ul_heldlockcnt = nlocks = INITIAL_LOCKS; 3040883492d5Sraf lockptr = lmalloc(nlocks * sizeof (mutex_t *)); 3041883492d5Sraf /* 3042883492d5Sraf * The single entry becomes the first entry in the array. 3043883492d5Sraf */ 3044883492d5Sraf *lockptr = self->ul_heldlocks.single; 3045883492d5Sraf self->ul_heldlocks.array = lockptr; 3046883492d5Sraf /* 3047883492d5Sraf * Return the next available entry in the array. 3048883492d5Sraf */ 3049883492d5Sraf *++lockptr = lock; 3050883492d5Sraf return (lockptr); 3051883492d5Sraf } 3052883492d5Sraf /* 3053883492d5Sraf * Reallocate the array, double the size each time. 3054883492d5Sraf */ 3055883492d5Sraf lockptr = lmalloc(nlocks * 2 * sizeof (mutex_t *)); 30568cd45542Sraf (void) memcpy(lockptr, self->ul_heldlocks.array, 3057883492d5Sraf nlocks * sizeof (mutex_t *)); 3058883492d5Sraf lfree(self->ul_heldlocks.array, nlocks * sizeof (mutex_t *)); 3059883492d5Sraf self->ul_heldlocks.array = lockptr; 3060883492d5Sraf self->ul_heldlockcnt *= 2; 3061883492d5Sraf /* 3062883492d5Sraf * Return the next available entry in the newly allocated array. 3063883492d5Sraf */ 3064883492d5Sraf *(lockptr += nlocks) = lock; 3065883492d5Sraf return (lockptr); 3066883492d5Sraf } 3067883492d5Sraf 3068883492d5Sraf /* 3069883492d5Sraf * Insert 'lock' into our list of held locks. 3070883492d5Sraf * Currently only used for LOCK_ROBUST mutexes. 3071883492d5Sraf */ 3072883492d5Sraf void 3073883492d5Sraf remember_lock(mutex_t *lock) 3074883492d5Sraf { 3075883492d5Sraf (void) find_lock_entry(lock); 3076883492d5Sraf } 3077883492d5Sraf 3078883492d5Sraf /* 3079883492d5Sraf * Remove 'lock' from our list of held locks. 3080883492d5Sraf * Currently only used for LOCK_ROBUST mutexes. 3081883492d5Sraf */ 3082883492d5Sraf void 3083883492d5Sraf forget_lock(mutex_t *lock) 3084883492d5Sraf { 3085883492d5Sraf *find_lock_entry(lock) = NULL; 3086883492d5Sraf } 3087883492d5Sraf 3088883492d5Sraf /* 3089883492d5Sraf * Free the array of held locks. 3090883492d5Sraf */ 3091883492d5Sraf void 3092883492d5Sraf heldlock_free(ulwp_t *ulwp) 3093883492d5Sraf { 3094883492d5Sraf uint_t nlocks; 3095883492d5Sraf 3096883492d5Sraf if ((nlocks = ulwp->ul_heldlockcnt) != 0) 3097883492d5Sraf lfree(ulwp->ul_heldlocks.array, nlocks * sizeof (mutex_t *)); 3098883492d5Sraf ulwp->ul_heldlockcnt = 0; 3099883492d5Sraf ulwp->ul_heldlocks.array = NULL; 3100883492d5Sraf } 3101883492d5Sraf 3102883492d5Sraf /* 3103883492d5Sraf * Mark all held LOCK_ROBUST mutexes LOCK_OWNERDEAD. 3104883492d5Sraf * Called from _thrp_exit() to deal with abandoned locks. 3105883492d5Sraf */ 3106883492d5Sraf void 3107883492d5Sraf heldlock_exit(void) 3108883492d5Sraf { 3109883492d5Sraf ulwp_t *self = curthread; 3110883492d5Sraf mutex_t **lockptr; 3111883492d5Sraf uint_t nlocks; 3112883492d5Sraf mutex_t *mp; 3113883492d5Sraf 3114883492d5Sraf if ((nlocks = self->ul_heldlockcnt) != 0) 3115883492d5Sraf lockptr = self->ul_heldlocks.array; 3116883492d5Sraf else { 3117883492d5Sraf nlocks = 1; 3118883492d5Sraf lockptr = &self->ul_heldlocks.single; 3119883492d5Sraf } 3120883492d5Sraf 3121883492d5Sraf for (; nlocks; nlocks--, lockptr++) { 3122883492d5Sraf /* 3123883492d5Sraf * The kernel takes care of transitioning held 3124883492d5Sraf * LOCK_PRIO_INHERIT mutexes to LOCK_OWNERDEAD. 3125883492d5Sraf * We avoid that case here. 3126883492d5Sraf */ 3127883492d5Sraf if ((mp = *lockptr) != NULL && 31287257d1b4Sraf mutex_held(mp) && 3129883492d5Sraf (mp->mutex_type & (LOCK_ROBUST | LOCK_PRIO_INHERIT)) == 3130883492d5Sraf LOCK_ROBUST) { 3131883492d5Sraf mp->mutex_rcount = 0; 3132883492d5Sraf if (!(mp->mutex_flag & LOCK_UNMAPPED)) 3133883492d5Sraf mp->mutex_flag |= LOCK_OWNERDEAD; 3134883492d5Sraf (void) mutex_unlock_internal(mp, 1); 3135883492d5Sraf } 3136883492d5Sraf } 3137883492d5Sraf 3138883492d5Sraf heldlock_free(self); 3139883492d5Sraf } 3140883492d5Sraf 31417257d1b4Sraf #pragma weak _cond_init = cond_init 31427c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 31437c478bd9Sstevel@tonic-gate int 31447257d1b4Sraf cond_init(cond_t *cvp, int type, void *arg) 31457c478bd9Sstevel@tonic-gate { 31467c478bd9Sstevel@tonic-gate if (type != USYNC_THREAD && type != USYNC_PROCESS) 31477c478bd9Sstevel@tonic-gate return (EINVAL); 31488cd45542Sraf (void) memset(cvp, 0, sizeof (*cvp)); 31497c478bd9Sstevel@tonic-gate cvp->cond_type = (uint16_t)type; 31507c478bd9Sstevel@tonic-gate cvp->cond_magic = COND_MAGIC; 31517c5714f6Sraf 31527c5714f6Sraf /* 31537c5714f6Sraf * This should be at the beginning of the function, 31547c5714f6Sraf * but for the sake of old broken applications that 31557c5714f6Sraf * do not have proper alignment for their condvars 31567c5714f6Sraf * (and don't check the return code from cond_init), 31577c5714f6Sraf * we put it here, after initializing the condvar regardless. 31587c5714f6Sraf */ 31597c5714f6Sraf if (((uintptr_t)cvp & (_LONG_LONG_ALIGNMENT - 1)) && 31607c5714f6Sraf curthread->ul_misaligned == 0) 31617c5714f6Sraf return (EINVAL); 31627c5714f6Sraf 31637c478bd9Sstevel@tonic-gate return (0); 31647c478bd9Sstevel@tonic-gate } 31657c478bd9Sstevel@tonic-gate 31667c478bd9Sstevel@tonic-gate /* 31677c478bd9Sstevel@tonic-gate * cond_sleep_queue(): utility function for cond_wait_queue(). 31687c478bd9Sstevel@tonic-gate * 31697c478bd9Sstevel@tonic-gate * Go to sleep on a condvar sleep queue, expect to be waked up 31707c478bd9Sstevel@tonic-gate * by someone calling cond_signal() or cond_broadcast() or due 31717c478bd9Sstevel@tonic-gate * to receiving a UNIX signal or being cancelled, or just simply 31727c478bd9Sstevel@tonic-gate * due to a spurious wakeup (like someome calling forkall()). 31737c478bd9Sstevel@tonic-gate * 31747c478bd9Sstevel@tonic-gate * The associated mutex is *not* reacquired before returning. 31757c478bd9Sstevel@tonic-gate * That must be done by the caller of cond_sleep_queue(). 31767c478bd9Sstevel@tonic-gate */ 3177883492d5Sraf static int 31787c478bd9Sstevel@tonic-gate cond_sleep_queue(cond_t *cvp, mutex_t *mp, timespec_t *tsp) 31797c478bd9Sstevel@tonic-gate { 31807c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 31817c478bd9Sstevel@tonic-gate queue_head_t *qp; 31827c478bd9Sstevel@tonic-gate queue_head_t *mqp; 31837c478bd9Sstevel@tonic-gate lwpid_t lwpid; 31847c478bd9Sstevel@tonic-gate int signalled; 31857c478bd9Sstevel@tonic-gate int error; 3186d4204c85Sraf int cv_wake; 3187883492d5Sraf int release_all; 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate /* 31907c478bd9Sstevel@tonic-gate * Put ourself on the CV sleep queue, unlock the mutex, then 31917c478bd9Sstevel@tonic-gate * park ourself and unpark a candidate lwp to grab the mutex. 31927c478bd9Sstevel@tonic-gate * We must go onto the CV sleep queue before dropping the 31937c478bd9Sstevel@tonic-gate * mutex in order to guarantee atomicity of the operation. 31947c478bd9Sstevel@tonic-gate */ 31957c478bd9Sstevel@tonic-gate self->ul_sp = stkptr(); 31967c478bd9Sstevel@tonic-gate qp = queue_lock(cvp, CV); 3197d4204c85Sraf enqueue(qp, self, 0); 31987c478bd9Sstevel@tonic-gate cvp->cond_waiters_user = 1; 31997c478bd9Sstevel@tonic-gate self->ul_cvmutex = mp; 3200d4204c85Sraf self->ul_cv_wake = cv_wake = (tsp != NULL); 32017c478bd9Sstevel@tonic-gate self->ul_signalled = 0; 3202883492d5Sraf if (mp->mutex_flag & LOCK_OWNERDEAD) { 3203883492d5Sraf mp->mutex_flag &= ~LOCK_OWNERDEAD; 3204883492d5Sraf mp->mutex_flag |= LOCK_NOTRECOVERABLE; 3205883492d5Sraf } 3206883492d5Sraf release_all = ((mp->mutex_flag & LOCK_NOTRECOVERABLE) != 0); 3207883492d5Sraf lwpid = mutex_unlock_queue(mp, release_all); 32087c478bd9Sstevel@tonic-gate for (;;) { 32097c478bd9Sstevel@tonic-gate set_parking_flag(self, 1); 32107c478bd9Sstevel@tonic-gate queue_unlock(qp); 32117c478bd9Sstevel@tonic-gate if (lwpid != 0) { 32127c478bd9Sstevel@tonic-gate lwpid = preempt_unpark(self, lwpid); 32137c478bd9Sstevel@tonic-gate preempt(self); 32147c478bd9Sstevel@tonic-gate } 32157c478bd9Sstevel@tonic-gate /* 32167c478bd9Sstevel@tonic-gate * We may have a deferred signal present, 32177c478bd9Sstevel@tonic-gate * in which case we should return EINTR. 32187c478bd9Sstevel@tonic-gate * Also, we may have received a SIGCANCEL; if so 32197c478bd9Sstevel@tonic-gate * and we are cancelable we should return EINTR. 32207c478bd9Sstevel@tonic-gate * We force an immediate EINTR return from 32217c478bd9Sstevel@tonic-gate * __lwp_park() by turning our parking flag off. 32227c478bd9Sstevel@tonic-gate */ 32237c478bd9Sstevel@tonic-gate if (self->ul_cursig != 0 || 32247c478bd9Sstevel@tonic-gate (self->ul_cancelable && self->ul_cancel_pending)) 32257c478bd9Sstevel@tonic-gate set_parking_flag(self, 0); 32267c478bd9Sstevel@tonic-gate /* 32277c478bd9Sstevel@tonic-gate * __lwp_park() will return the residual time in tsp 32287c478bd9Sstevel@tonic-gate * if we are unparked before the timeout expires. 32297c478bd9Sstevel@tonic-gate */ 32307c478bd9Sstevel@tonic-gate error = __lwp_park(tsp, lwpid); 32317c478bd9Sstevel@tonic-gate set_parking_flag(self, 0); 32327c478bd9Sstevel@tonic-gate lwpid = 0; /* unpark the other lwp only once */ 32337c478bd9Sstevel@tonic-gate /* 32347c478bd9Sstevel@tonic-gate * We were waked up by cond_signal(), cond_broadcast(), 32357c478bd9Sstevel@tonic-gate * by an interrupt or timeout (EINTR or ETIME), 32367c478bd9Sstevel@tonic-gate * or we may just have gotten a spurious wakeup. 32377c478bd9Sstevel@tonic-gate */ 32387c478bd9Sstevel@tonic-gate qp = queue_lock(cvp, CV); 3239d4204c85Sraf if (!cv_wake) 32407c478bd9Sstevel@tonic-gate mqp = queue_lock(mp, MX); 32417c478bd9Sstevel@tonic-gate if (self->ul_sleepq == NULL) 32427c478bd9Sstevel@tonic-gate break; 32437c478bd9Sstevel@tonic-gate /* 32447c478bd9Sstevel@tonic-gate * We are on either the condvar sleep queue or the 32452be60c5eSraf * mutex sleep queue. Break out of the sleep if we 32462be60c5eSraf * were interrupted or we timed out (EINTR or ETIME). 32477c478bd9Sstevel@tonic-gate * Else this is a spurious wakeup; continue the loop. 32487c478bd9Sstevel@tonic-gate */ 3249d4204c85Sraf if (!cv_wake && self->ul_sleepq == mqp) { /* mutex queue */ 32502be60c5eSraf if (error) { 3251d4204c85Sraf mp->mutex_waiters = dequeue_self(mqp); 32522be60c5eSraf break; 32532be60c5eSraf } 32542be60c5eSraf tsp = NULL; /* no more timeout */ 32552be60c5eSraf } else if (self->ul_sleepq == qp) { /* condvar queue */ 32567c478bd9Sstevel@tonic-gate if (error) { 3257d4204c85Sraf cvp->cond_waiters_user = dequeue_self(qp); 32587c478bd9Sstevel@tonic-gate break; 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate /* 32617c478bd9Sstevel@tonic-gate * Else a spurious wakeup on the condvar queue. 32627c478bd9Sstevel@tonic-gate * __lwp_park() has already adjusted the timeout. 32637c478bd9Sstevel@tonic-gate */ 32647c478bd9Sstevel@tonic-gate } else { 32657c478bd9Sstevel@tonic-gate thr_panic("cond_sleep_queue(): thread not on queue"); 32667c478bd9Sstevel@tonic-gate } 3267d4204c85Sraf if (!cv_wake) 32687c478bd9Sstevel@tonic-gate queue_unlock(mqp); 32697c478bd9Sstevel@tonic-gate } 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate self->ul_sp = 0; 3272d4204c85Sraf self->ul_cv_wake = 0; 3273d4204c85Sraf ASSERT(self->ul_cvmutex == NULL); 32747c478bd9Sstevel@tonic-gate ASSERT(self->ul_sleepq == NULL && self->ul_link == NULL && 32757c478bd9Sstevel@tonic-gate self->ul_wchan == NULL); 32767c478bd9Sstevel@tonic-gate 32777c478bd9Sstevel@tonic-gate signalled = self->ul_signalled; 32787c478bd9Sstevel@tonic-gate self->ul_signalled = 0; 32797c478bd9Sstevel@tonic-gate queue_unlock(qp); 3280d4204c85Sraf if (!cv_wake) 32817c478bd9Sstevel@tonic-gate queue_unlock(mqp); 32827c478bd9Sstevel@tonic-gate 32837c478bd9Sstevel@tonic-gate /* 32847c478bd9Sstevel@tonic-gate * If we were concurrently cond_signal()d and any of: 32857c478bd9Sstevel@tonic-gate * received a UNIX signal, were cancelled, or got a timeout, 32867c478bd9Sstevel@tonic-gate * then perform another cond_signal() to avoid consuming it. 32877c478bd9Sstevel@tonic-gate */ 32887c478bd9Sstevel@tonic-gate if (error && signalled) 32897257d1b4Sraf (void) cond_signal(cvp); 32907c478bd9Sstevel@tonic-gate 32917c478bd9Sstevel@tonic-gate return (error); 32927c478bd9Sstevel@tonic-gate } 32937c478bd9Sstevel@tonic-gate 32947c5714f6Sraf static void 32957c5714f6Sraf cond_wait_check_alignment(cond_t *cvp, mutex_t *mp) 32967c5714f6Sraf { 32977c5714f6Sraf if ((uintptr_t)mp & (_LONG_LONG_ALIGNMENT - 1)) 32987c5714f6Sraf lock_error(mp, "cond_wait", cvp, "mutex is misaligned"); 32997c5714f6Sraf if ((uintptr_t)cvp & (_LONG_LONG_ALIGNMENT - 1)) 33007c5714f6Sraf lock_error(mp, "cond_wait", cvp, "condvar is misaligned"); 33017c5714f6Sraf } 33027c5714f6Sraf 33037c478bd9Sstevel@tonic-gate int 33045d1dd9a9Sraf cond_wait_queue(cond_t *cvp, mutex_t *mp, timespec_t *tsp) 33057c478bd9Sstevel@tonic-gate { 33067c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 33077c478bd9Sstevel@tonic-gate int error; 3308883492d5Sraf int merror; 33097c478bd9Sstevel@tonic-gate 33107c5714f6Sraf if (self->ul_error_detection && self->ul_misaligned == 0) 33117c5714f6Sraf cond_wait_check_alignment(cvp, mp); 33127c5714f6Sraf 33137c478bd9Sstevel@tonic-gate /* 33147c478bd9Sstevel@tonic-gate * The old thread library was programmed to defer signals 33157c478bd9Sstevel@tonic-gate * while in cond_wait() so that the associated mutex would 33167c478bd9Sstevel@tonic-gate * be guaranteed to be held when the application signal 33177c478bd9Sstevel@tonic-gate * handler was invoked. 33187c478bd9Sstevel@tonic-gate * 33197c478bd9Sstevel@tonic-gate * We do not behave this way by default; the state of the 33207c478bd9Sstevel@tonic-gate * associated mutex in the signal handler is undefined. 33217c478bd9Sstevel@tonic-gate * 33227c478bd9Sstevel@tonic-gate * To accommodate applications that depend on the old 33237c478bd9Sstevel@tonic-gate * behavior, the _THREAD_COND_WAIT_DEFER environment 33247c478bd9Sstevel@tonic-gate * variable can be set to 1 and we will behave in the 33257c478bd9Sstevel@tonic-gate * old way with respect to cond_wait(). 33267c478bd9Sstevel@tonic-gate */ 33277c478bd9Sstevel@tonic-gate if (self->ul_cond_wait_defer) 33287c478bd9Sstevel@tonic-gate sigoff(self); 33297c478bd9Sstevel@tonic-gate 33307c478bd9Sstevel@tonic-gate error = cond_sleep_queue(cvp, mp, tsp); 33317c478bd9Sstevel@tonic-gate 33327c478bd9Sstevel@tonic-gate /* 33337c478bd9Sstevel@tonic-gate * Reacquire the mutex. 33347c478bd9Sstevel@tonic-gate */ 33355d1dd9a9Sraf if ((merror = mutex_lock_impl(mp, NULL)) != 0) 3336883492d5Sraf error = merror; 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate /* 33397c478bd9Sstevel@tonic-gate * Take any deferred signal now, after we have reacquired the mutex. 33407c478bd9Sstevel@tonic-gate */ 33417c478bd9Sstevel@tonic-gate if (self->ul_cond_wait_defer) 33427c478bd9Sstevel@tonic-gate sigon(self); 33437c478bd9Sstevel@tonic-gate 33447c478bd9Sstevel@tonic-gate return (error); 33457c478bd9Sstevel@tonic-gate } 33467c478bd9Sstevel@tonic-gate 33477c478bd9Sstevel@tonic-gate /* 33487c478bd9Sstevel@tonic-gate * cond_sleep_kernel(): utility function for cond_wait_kernel(). 33497c478bd9Sstevel@tonic-gate * See the comment ahead of cond_sleep_queue(), above. 33507c478bd9Sstevel@tonic-gate */ 3351883492d5Sraf static int 33527c478bd9Sstevel@tonic-gate cond_sleep_kernel(cond_t *cvp, mutex_t *mp, timespec_t *tsp) 33537c478bd9Sstevel@tonic-gate { 33547c478bd9Sstevel@tonic-gate int mtype = mp->mutex_type; 33557c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 33567c478bd9Sstevel@tonic-gate int error; 33577c478bd9Sstevel@tonic-gate 3358883492d5Sraf if ((mtype & LOCK_PRIO_PROTECT) && _ceil_mylist_del(mp)) 33597c478bd9Sstevel@tonic-gate _ceil_prio_waive(); 33607c478bd9Sstevel@tonic-gate 33617c478bd9Sstevel@tonic-gate self->ul_sp = stkptr(); 33627c478bd9Sstevel@tonic-gate self->ul_wchan = cvp; 3363328cc3e9SRoger A. Faulkner sigoff(self); 33647c478bd9Sstevel@tonic-gate mp->mutex_owner = 0; 336531db3c26Sraf /* mp->mutex_ownerpid is cleared by ___lwp_cond_wait() */ 3366d4204c85Sraf if (mtype & LOCK_PRIO_INHERIT) { 33677c478bd9Sstevel@tonic-gate mp->mutex_lockw = LOCKCLEAR; 3368d4204c85Sraf self->ul_pilocks--; 3369d4204c85Sraf } 33707c478bd9Sstevel@tonic-gate /* 33717c478bd9Sstevel@tonic-gate * ___lwp_cond_wait() returns immediately with EINTR if 33727c478bd9Sstevel@tonic-gate * set_parking_flag(self,0) is called on this lwp before it 33737c478bd9Sstevel@tonic-gate * goes to sleep in the kernel. sigacthandler() calls this 33747c478bd9Sstevel@tonic-gate * when a deferred signal is noted. This assures that we don't 33757c478bd9Sstevel@tonic-gate * get stuck in ___lwp_cond_wait() with all signals blocked 33767c478bd9Sstevel@tonic-gate * due to taking a deferred signal before going to sleep. 33777c478bd9Sstevel@tonic-gate */ 33787c478bd9Sstevel@tonic-gate set_parking_flag(self, 1); 33797c478bd9Sstevel@tonic-gate if (self->ul_cursig != 0 || 33807c478bd9Sstevel@tonic-gate (self->ul_cancelable && self->ul_cancel_pending)) 33817c478bd9Sstevel@tonic-gate set_parking_flag(self, 0); 33827c478bd9Sstevel@tonic-gate error = ___lwp_cond_wait(cvp, mp, tsp, 1); 33837c478bd9Sstevel@tonic-gate set_parking_flag(self, 0); 3384328cc3e9SRoger A. Faulkner sigon(self); 33857c478bd9Sstevel@tonic-gate self->ul_sp = 0; 33867c478bd9Sstevel@tonic-gate self->ul_wchan = NULL; 33877c478bd9Sstevel@tonic-gate return (error); 33887c478bd9Sstevel@tonic-gate } 33897c478bd9Sstevel@tonic-gate 33907c478bd9Sstevel@tonic-gate int 33917c478bd9Sstevel@tonic-gate cond_wait_kernel(cond_t *cvp, mutex_t *mp, timespec_t *tsp) 33927c478bd9Sstevel@tonic-gate { 33937c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 33947c478bd9Sstevel@tonic-gate int error; 33957c478bd9Sstevel@tonic-gate int merror; 33967c478bd9Sstevel@tonic-gate 33977c5714f6Sraf if (self->ul_error_detection && self->ul_misaligned == 0) 33987c5714f6Sraf cond_wait_check_alignment(cvp, mp); 33997c5714f6Sraf 34007c478bd9Sstevel@tonic-gate /* 34017c478bd9Sstevel@tonic-gate * See the large comment in cond_wait_queue(), above. 34027c478bd9Sstevel@tonic-gate */ 34037c478bd9Sstevel@tonic-gate if (self->ul_cond_wait_defer) 34047c478bd9Sstevel@tonic-gate sigoff(self); 34057c478bd9Sstevel@tonic-gate 34067c478bd9Sstevel@tonic-gate error = cond_sleep_kernel(cvp, mp, tsp); 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate /* 34097c478bd9Sstevel@tonic-gate * Override the return code from ___lwp_cond_wait() 34107c478bd9Sstevel@tonic-gate * with any non-zero return code from mutex_lock(). 34117c478bd9Sstevel@tonic-gate * This addresses robust lock failures in particular; 34127c478bd9Sstevel@tonic-gate * the caller must see the EOWNERDEAD or ENOTRECOVERABLE 34137c478bd9Sstevel@tonic-gate * errors in order to take corrective action. 34147c478bd9Sstevel@tonic-gate */ 34155d1dd9a9Sraf if ((merror = mutex_lock_impl(mp, NULL)) != 0) 34167c478bd9Sstevel@tonic-gate error = merror; 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate /* 34197c478bd9Sstevel@tonic-gate * Take any deferred signal now, after we have reacquired the mutex. 34207c478bd9Sstevel@tonic-gate */ 34217c478bd9Sstevel@tonic-gate if (self->ul_cond_wait_defer) 34227c478bd9Sstevel@tonic-gate sigon(self); 34237c478bd9Sstevel@tonic-gate 34247c478bd9Sstevel@tonic-gate return (error); 34257c478bd9Sstevel@tonic-gate } 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate /* 34287257d1b4Sraf * Common code for cond_wait() and cond_timedwait() 34297c478bd9Sstevel@tonic-gate */ 34307c478bd9Sstevel@tonic-gate int 34317c478bd9Sstevel@tonic-gate cond_wait_common(cond_t *cvp, mutex_t *mp, timespec_t *tsp) 34327c478bd9Sstevel@tonic-gate { 34337c478bd9Sstevel@tonic-gate int mtype = mp->mutex_type; 34347c478bd9Sstevel@tonic-gate hrtime_t begin_sleep = 0; 34357c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 34367c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 34377c478bd9Sstevel@tonic-gate tdb_cond_stats_t *csp = COND_STATS(cvp, udp); 34387c478bd9Sstevel@tonic-gate tdb_mutex_stats_t *msp = MUTEX_STATS(mp, udp); 34397c478bd9Sstevel@tonic-gate uint8_t rcount; 34407c478bd9Sstevel@tonic-gate int error = 0; 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate /* 34437c478bd9Sstevel@tonic-gate * The SUSV3 Posix spec for pthread_cond_timedwait() states: 34447c478bd9Sstevel@tonic-gate * Except in the case of [ETIMEDOUT], all these error checks 34457c478bd9Sstevel@tonic-gate * shall act as if they were performed immediately at the 34467c478bd9Sstevel@tonic-gate * beginning of processing for the function and shall cause 34477c478bd9Sstevel@tonic-gate * an error return, in effect, prior to modifying the state 34487c478bd9Sstevel@tonic-gate * of the mutex specified by mutex or the condition variable 34497c478bd9Sstevel@tonic-gate * specified by cond. 34507c478bd9Sstevel@tonic-gate * Therefore, we must return EINVAL now if the timout is invalid. 34517c478bd9Sstevel@tonic-gate */ 34527c478bd9Sstevel@tonic-gate if (tsp != NULL && 34537c478bd9Sstevel@tonic-gate (tsp->tv_sec < 0 || (ulong_t)tsp->tv_nsec >= NANOSEC)) 34547c478bd9Sstevel@tonic-gate return (EINVAL); 34557c478bd9Sstevel@tonic-gate 34567c478bd9Sstevel@tonic-gate if (__td_event_report(self, TD_SLEEP, udp)) { 34577c478bd9Sstevel@tonic-gate self->ul_sp = stkptr(); 34587c478bd9Sstevel@tonic-gate self->ul_wchan = cvp; 34597c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_SLEEP; 34607c478bd9Sstevel@tonic-gate self->ul_td_evbuf.eventdata = cvp; 34617c478bd9Sstevel@tonic-gate tdb_event(TD_SLEEP, udp); 34627c478bd9Sstevel@tonic-gate self->ul_sp = 0; 34637c478bd9Sstevel@tonic-gate } 34647c478bd9Sstevel@tonic-gate if (csp) { 34657c478bd9Sstevel@tonic-gate if (tsp) 34667c478bd9Sstevel@tonic-gate tdb_incr(csp->cond_timedwait); 34677c478bd9Sstevel@tonic-gate else 34687c478bd9Sstevel@tonic-gate tdb_incr(csp->cond_wait); 34697c478bd9Sstevel@tonic-gate } 34707c478bd9Sstevel@tonic-gate if (msp) 34717c478bd9Sstevel@tonic-gate begin_sleep = record_hold_time(msp); 34727c478bd9Sstevel@tonic-gate else if (csp) 34737c478bd9Sstevel@tonic-gate begin_sleep = gethrtime(); 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate if (self->ul_error_detection) { 34767257d1b4Sraf if (!mutex_held(mp)) 34777c478bd9Sstevel@tonic-gate lock_error(mp, "cond_wait", cvp, NULL); 34787c478bd9Sstevel@tonic-gate if ((mtype & LOCK_RECURSIVE) && mp->mutex_rcount != 0) 34797c478bd9Sstevel@tonic-gate lock_error(mp, "recursive mutex in cond_wait", 34807c478bd9Sstevel@tonic-gate cvp, NULL); 34817c478bd9Sstevel@tonic-gate if (cvp->cond_type & USYNC_PROCESS) { 3482883492d5Sraf if (!(mtype & USYNC_PROCESS)) 34837c478bd9Sstevel@tonic-gate lock_error(mp, "cond_wait", cvp, 34847c478bd9Sstevel@tonic-gate "condvar process-shared, " 34857c478bd9Sstevel@tonic-gate "mutex process-private"); 34867c478bd9Sstevel@tonic-gate } else { 3487883492d5Sraf if (mtype & USYNC_PROCESS) 34887c478bd9Sstevel@tonic-gate lock_error(mp, "cond_wait", cvp, 34897c478bd9Sstevel@tonic-gate "condvar process-private, " 34907c478bd9Sstevel@tonic-gate "mutex process-shared"); 34917c478bd9Sstevel@tonic-gate } 34927c478bd9Sstevel@tonic-gate } 34937c478bd9Sstevel@tonic-gate 34947c478bd9Sstevel@tonic-gate /* 34957c478bd9Sstevel@tonic-gate * We deal with recursive mutexes by completely 34967c478bd9Sstevel@tonic-gate * dropping the lock and restoring the recursion 34977c478bd9Sstevel@tonic-gate * count after waking up. This is arguably wrong, 34987c478bd9Sstevel@tonic-gate * but it obeys the principle of least astonishment. 34997c478bd9Sstevel@tonic-gate */ 35007c478bd9Sstevel@tonic-gate rcount = mp->mutex_rcount; 35017c478bd9Sstevel@tonic-gate mp->mutex_rcount = 0; 3502883492d5Sraf if ((mtype & 3503883492d5Sraf (USYNC_PROCESS | LOCK_PRIO_INHERIT | LOCK_PRIO_PROTECT)) | 35047c478bd9Sstevel@tonic-gate (cvp->cond_type & USYNC_PROCESS)) 35057c478bd9Sstevel@tonic-gate error = cond_wait_kernel(cvp, mp, tsp); 35067c478bd9Sstevel@tonic-gate else 35075d1dd9a9Sraf error = cond_wait_queue(cvp, mp, tsp); 35087c478bd9Sstevel@tonic-gate mp->mutex_rcount = rcount; 35097c478bd9Sstevel@tonic-gate 35107c478bd9Sstevel@tonic-gate if (csp) { 35117c478bd9Sstevel@tonic-gate hrtime_t lapse = gethrtime() - begin_sleep; 35127c478bd9Sstevel@tonic-gate if (tsp == NULL) 35137c478bd9Sstevel@tonic-gate csp->cond_wait_sleep_time += lapse; 35147c478bd9Sstevel@tonic-gate else { 35157c478bd9Sstevel@tonic-gate csp->cond_timedwait_sleep_time += lapse; 35167c478bd9Sstevel@tonic-gate if (error == ETIME) 35177c478bd9Sstevel@tonic-gate tdb_incr(csp->cond_timedwait_timeout); 35187c478bd9Sstevel@tonic-gate } 35197c478bd9Sstevel@tonic-gate } 35207c478bd9Sstevel@tonic-gate return (error); 35217c478bd9Sstevel@tonic-gate } 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate /* 35247257d1b4Sraf * cond_wait() is a cancellation point but __cond_wait() is not. 35257257d1b4Sraf * Internally, libc calls the non-cancellation version. 3526a574db85Sraf * Other libraries need to use pthread_setcancelstate(), as appropriate, 3527a574db85Sraf * since __cond_wait() is not exported from libc. 35287c478bd9Sstevel@tonic-gate */ 35297c478bd9Sstevel@tonic-gate int 3530a574db85Sraf __cond_wait(cond_t *cvp, mutex_t *mp) 35317c478bd9Sstevel@tonic-gate { 35327c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 35337c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 35347c478bd9Sstevel@tonic-gate uberflags_t *gflags; 35357c478bd9Sstevel@tonic-gate 353680d89c86SRoger A. Faulkner if ((mp->mutex_type & (LOCK_ERRORCHECK | LOCK_ROBUST)) && 353780d89c86SRoger A. Faulkner !mutex_held(mp)) 353880d89c86SRoger A. Faulkner return (EPERM); 353980d89c86SRoger A. Faulkner 35407c478bd9Sstevel@tonic-gate /* 35417c478bd9Sstevel@tonic-gate * Optimize the common case of USYNC_THREAD plus 35427c478bd9Sstevel@tonic-gate * no error detection, no lock statistics, and no event tracing. 35437c478bd9Sstevel@tonic-gate */ 35447c478bd9Sstevel@tonic-gate if ((gflags = self->ul_schedctl_called) != NULL && 35457c478bd9Sstevel@tonic-gate (cvp->cond_type | mp->mutex_type | gflags->uf_trs_ted | 35467c478bd9Sstevel@tonic-gate self->ul_td_events_enable | 35477c478bd9Sstevel@tonic-gate udp->tdb.tdb_ev_global_mask.event_bits[0]) == 0) 35485d1dd9a9Sraf return (cond_wait_queue(cvp, mp, NULL)); 35497c478bd9Sstevel@tonic-gate 35507c478bd9Sstevel@tonic-gate /* 35517c478bd9Sstevel@tonic-gate * Else do it the long way. 35527c478bd9Sstevel@tonic-gate */ 35537c478bd9Sstevel@tonic-gate return (cond_wait_common(cvp, mp, NULL)); 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate 35567257d1b4Sraf #pragma weak _cond_wait = cond_wait 35577c478bd9Sstevel@tonic-gate int 35587257d1b4Sraf cond_wait(cond_t *cvp, mutex_t *mp) 35597c478bd9Sstevel@tonic-gate { 35607c478bd9Sstevel@tonic-gate int error; 35617c478bd9Sstevel@tonic-gate 35627c478bd9Sstevel@tonic-gate _cancelon(); 3563a574db85Sraf error = __cond_wait(cvp, mp); 35647c478bd9Sstevel@tonic-gate if (error == EINTR) 35657c478bd9Sstevel@tonic-gate _canceloff(); 35667c478bd9Sstevel@tonic-gate else 35677c478bd9Sstevel@tonic-gate _canceloff_nocancel(); 35687c478bd9Sstevel@tonic-gate return (error); 35697c478bd9Sstevel@tonic-gate } 35707c478bd9Sstevel@tonic-gate 3571a574db85Sraf /* 3572a574db85Sraf * pthread_cond_wait() is a cancellation point. 3573a574db85Sraf */ 35747c478bd9Sstevel@tonic-gate int 35757257d1b4Sraf pthread_cond_wait(pthread_cond_t *_RESTRICT_KYWD cvp, 35767257d1b4Sraf pthread_mutex_t *_RESTRICT_KYWD mp) 35777c478bd9Sstevel@tonic-gate { 35787c478bd9Sstevel@tonic-gate int error; 35797c478bd9Sstevel@tonic-gate 35807257d1b4Sraf error = cond_wait((cond_t *)cvp, (mutex_t *)mp); 35817c478bd9Sstevel@tonic-gate return ((error == EINTR)? 0 : error); 35827c478bd9Sstevel@tonic-gate } 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate /* 35857257d1b4Sraf * cond_timedwait() is a cancellation point but __cond_timedwait() is not. 35867c478bd9Sstevel@tonic-gate */ 35877c478bd9Sstevel@tonic-gate int 3588a574db85Sraf __cond_timedwait(cond_t *cvp, mutex_t *mp, const timespec_t *abstime) 35897c478bd9Sstevel@tonic-gate { 35907c478bd9Sstevel@tonic-gate clockid_t clock_id = cvp->cond_clockid; 35917c478bd9Sstevel@tonic-gate timespec_t reltime; 35927c478bd9Sstevel@tonic-gate int error; 35937c478bd9Sstevel@tonic-gate 359480d89c86SRoger A. Faulkner if ((mp->mutex_type & (LOCK_ERRORCHECK | LOCK_ROBUST)) && 359580d89c86SRoger A. Faulkner !mutex_held(mp)) 359680d89c86SRoger A. Faulkner return (EPERM); 359780d89c86SRoger A. Faulkner 35987c478bd9Sstevel@tonic-gate if (clock_id != CLOCK_REALTIME && clock_id != CLOCK_HIGHRES) 35997c478bd9Sstevel@tonic-gate clock_id = CLOCK_REALTIME; 36007c478bd9Sstevel@tonic-gate abstime_to_reltime(clock_id, abstime, &reltime); 36017c478bd9Sstevel@tonic-gate error = cond_wait_common(cvp, mp, &reltime); 36027c478bd9Sstevel@tonic-gate if (error == ETIME && clock_id == CLOCK_HIGHRES) { 36037c478bd9Sstevel@tonic-gate /* 36047c478bd9Sstevel@tonic-gate * Don't return ETIME if we didn't really get a timeout. 36057c478bd9Sstevel@tonic-gate * This can happen if we return because someone resets 36067c478bd9Sstevel@tonic-gate * the system clock. Just return zero in this case, 36077c478bd9Sstevel@tonic-gate * giving a spurious wakeup but not a timeout. 36087c478bd9Sstevel@tonic-gate */ 36097c478bd9Sstevel@tonic-gate if ((hrtime_t)(uint32_t)abstime->tv_sec * NANOSEC + 36107c478bd9Sstevel@tonic-gate abstime->tv_nsec > gethrtime()) 36117c478bd9Sstevel@tonic-gate error = 0; 36127c478bd9Sstevel@tonic-gate } 36137c478bd9Sstevel@tonic-gate return (error); 36147c478bd9Sstevel@tonic-gate } 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate int 36177257d1b4Sraf cond_timedwait(cond_t *cvp, mutex_t *mp, const timespec_t *abstime) 36187c478bd9Sstevel@tonic-gate { 36197c478bd9Sstevel@tonic-gate int error; 36207c478bd9Sstevel@tonic-gate 36217c478bd9Sstevel@tonic-gate _cancelon(); 3622a574db85Sraf error = __cond_timedwait(cvp, mp, abstime); 36237c478bd9Sstevel@tonic-gate if (error == EINTR) 36247c478bd9Sstevel@tonic-gate _canceloff(); 36257c478bd9Sstevel@tonic-gate else 36267c478bd9Sstevel@tonic-gate _canceloff_nocancel(); 36277c478bd9Sstevel@tonic-gate return (error); 36287c478bd9Sstevel@tonic-gate } 36297c478bd9Sstevel@tonic-gate 3630a574db85Sraf /* 3631a574db85Sraf * pthread_cond_timedwait() is a cancellation point. 3632a574db85Sraf */ 36337c478bd9Sstevel@tonic-gate int 36347257d1b4Sraf pthread_cond_timedwait(pthread_cond_t *_RESTRICT_KYWD cvp, 36357257d1b4Sraf pthread_mutex_t *_RESTRICT_KYWD mp, 36367257d1b4Sraf const struct timespec *_RESTRICT_KYWD abstime) 36377c478bd9Sstevel@tonic-gate { 36387c478bd9Sstevel@tonic-gate int error; 36397c478bd9Sstevel@tonic-gate 36407257d1b4Sraf error = cond_timedwait((cond_t *)cvp, (mutex_t *)mp, abstime); 36417c478bd9Sstevel@tonic-gate if (error == ETIME) 36427c478bd9Sstevel@tonic-gate error = ETIMEDOUT; 36437c478bd9Sstevel@tonic-gate else if (error == EINTR) 36447c478bd9Sstevel@tonic-gate error = 0; 36457c478bd9Sstevel@tonic-gate return (error); 36467c478bd9Sstevel@tonic-gate } 36477c478bd9Sstevel@tonic-gate 36487c478bd9Sstevel@tonic-gate /* 36497257d1b4Sraf * cond_reltimedwait() is a cancellation point but __cond_reltimedwait() is not. 36507c478bd9Sstevel@tonic-gate */ 36517c478bd9Sstevel@tonic-gate int 3652a574db85Sraf __cond_reltimedwait(cond_t *cvp, mutex_t *mp, const timespec_t *reltime) 36537c478bd9Sstevel@tonic-gate { 36547c478bd9Sstevel@tonic-gate timespec_t tslocal = *reltime; 36557c478bd9Sstevel@tonic-gate 365680d89c86SRoger A. Faulkner if ((mp->mutex_type & (LOCK_ERRORCHECK | LOCK_ROBUST)) && 365780d89c86SRoger A. Faulkner !mutex_held(mp)) 365880d89c86SRoger A. Faulkner return (EPERM); 365980d89c86SRoger A. Faulkner 36607c478bd9Sstevel@tonic-gate return (cond_wait_common(cvp, mp, &tslocal)); 36617c478bd9Sstevel@tonic-gate } 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate int 36647257d1b4Sraf cond_reltimedwait(cond_t *cvp, mutex_t *mp, const timespec_t *reltime) 36657c478bd9Sstevel@tonic-gate { 36667c478bd9Sstevel@tonic-gate int error; 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate _cancelon(); 3669a574db85Sraf error = __cond_reltimedwait(cvp, mp, reltime); 36707c478bd9Sstevel@tonic-gate if (error == EINTR) 36717c478bd9Sstevel@tonic-gate _canceloff(); 36727c478bd9Sstevel@tonic-gate else 36737c478bd9Sstevel@tonic-gate _canceloff_nocancel(); 36747c478bd9Sstevel@tonic-gate return (error); 36757c478bd9Sstevel@tonic-gate } 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate int 36787257d1b4Sraf pthread_cond_reltimedwait_np(pthread_cond_t *_RESTRICT_KYWD cvp, 36797257d1b4Sraf pthread_mutex_t *_RESTRICT_KYWD mp, 36807257d1b4Sraf const struct timespec *_RESTRICT_KYWD reltime) 36817c478bd9Sstevel@tonic-gate { 36827c478bd9Sstevel@tonic-gate int error; 36837c478bd9Sstevel@tonic-gate 36847257d1b4Sraf error = cond_reltimedwait((cond_t *)cvp, (mutex_t *)mp, reltime); 36857c478bd9Sstevel@tonic-gate if (error == ETIME) 36867c478bd9Sstevel@tonic-gate error = ETIMEDOUT; 36877c478bd9Sstevel@tonic-gate else if (error == EINTR) 36887c478bd9Sstevel@tonic-gate error = 0; 36897c478bd9Sstevel@tonic-gate return (error); 36907c478bd9Sstevel@tonic-gate } 36917c478bd9Sstevel@tonic-gate 36927257d1b4Sraf #pragma weak pthread_cond_signal = cond_signal 36937257d1b4Sraf #pragma weak _cond_signal = cond_signal 36947c478bd9Sstevel@tonic-gate int 36957257d1b4Sraf cond_signal(cond_t *cvp) 36967c478bd9Sstevel@tonic-gate { 36977c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 36987c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 36997c478bd9Sstevel@tonic-gate tdb_cond_stats_t *csp = COND_STATS(cvp, udp); 37007c478bd9Sstevel@tonic-gate int error = 0; 3701d4204c85Sraf int more; 3702d4204c85Sraf lwpid_t lwpid; 37037c478bd9Sstevel@tonic-gate queue_head_t *qp; 37047c478bd9Sstevel@tonic-gate mutex_t *mp; 37057c478bd9Sstevel@tonic-gate queue_head_t *mqp; 37067c478bd9Sstevel@tonic-gate ulwp_t **ulwpp; 37077c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 3708d4204c85Sraf ulwp_t *prev; 37097c478bd9Sstevel@tonic-gate 37107c478bd9Sstevel@tonic-gate if (csp) 37117c478bd9Sstevel@tonic-gate tdb_incr(csp->cond_signal); 37127c478bd9Sstevel@tonic-gate 37137c478bd9Sstevel@tonic-gate if (cvp->cond_waiters_kernel) /* someone sleeping in the kernel? */ 37147257d1b4Sraf error = _lwp_cond_signal(cvp); 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate if (!cvp->cond_waiters_user) /* no one sleeping at user-level */ 37177c478bd9Sstevel@tonic-gate return (error); 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate /* 37207c478bd9Sstevel@tonic-gate * Move someone from the condvar sleep queue to the mutex sleep 37217c478bd9Sstevel@tonic-gate * queue for the mutex that he will acquire on being waked up. 37227c478bd9Sstevel@tonic-gate * We can do this only if we own the mutex he will acquire. 37237c478bd9Sstevel@tonic-gate * If we do not own the mutex, or if his ul_cv_wake flag 37247c478bd9Sstevel@tonic-gate * is set, just dequeue and unpark him. 37257c478bd9Sstevel@tonic-gate */ 37267c478bd9Sstevel@tonic-gate qp = queue_lock(cvp, CV); 3727d4204c85Sraf ulwpp = queue_slot(qp, &prev, &more); 3728d4204c85Sraf cvp->cond_waiters_user = more; 3729d4204c85Sraf if (ulwpp == NULL) { /* no one on the sleep queue */ 37307c478bd9Sstevel@tonic-gate queue_unlock(qp); 37317c478bd9Sstevel@tonic-gate return (error); 37327c478bd9Sstevel@tonic-gate } 3733d4204c85Sraf ulwp = *ulwpp; 37347c478bd9Sstevel@tonic-gate 37357c478bd9Sstevel@tonic-gate /* 37367c478bd9Sstevel@tonic-gate * Inform the thread that he was the recipient of a cond_signal(). 37377c478bd9Sstevel@tonic-gate * This lets him deal with cond_signal() and, concurrently, 37387c478bd9Sstevel@tonic-gate * one or more of a cancellation, a UNIX signal, or a timeout. 37397c478bd9Sstevel@tonic-gate * These latter conditions must not consume a cond_signal(). 37407c478bd9Sstevel@tonic-gate */ 37417c478bd9Sstevel@tonic-gate ulwp->ul_signalled = 1; 37427c478bd9Sstevel@tonic-gate 37437c478bd9Sstevel@tonic-gate /* 37447c478bd9Sstevel@tonic-gate * Dequeue the waiter but leave his ul_sleepq non-NULL 37457c478bd9Sstevel@tonic-gate * while we move him to the mutex queue so that he can 37467c478bd9Sstevel@tonic-gate * deal properly with spurious wakeups. 37477c478bd9Sstevel@tonic-gate */ 3748d4204c85Sraf queue_unlink(qp, ulwpp, prev); 37497c478bd9Sstevel@tonic-gate 37507c478bd9Sstevel@tonic-gate mp = ulwp->ul_cvmutex; /* the mutex he will acquire */ 37517c478bd9Sstevel@tonic-gate ulwp->ul_cvmutex = NULL; 37527c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 37537c478bd9Sstevel@tonic-gate 37547c478bd9Sstevel@tonic-gate if (ulwp->ul_cv_wake || !MUTEX_OWNED(mp, self)) { 3755d4204c85Sraf /* just wake him up */ 3756d4204c85Sraf lwpid = ulwp->ul_lwpid; 37577c478bd9Sstevel@tonic-gate no_preempt(self); 37587c478bd9Sstevel@tonic-gate ulwp->ul_sleepq = NULL; 37597c478bd9Sstevel@tonic-gate ulwp->ul_wchan = NULL; 37607c478bd9Sstevel@tonic-gate queue_unlock(qp); 37617c478bd9Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 37627c478bd9Sstevel@tonic-gate preempt(self); 37637c478bd9Sstevel@tonic-gate } else { 3764d4204c85Sraf /* move him to the mutex queue */ 37657c478bd9Sstevel@tonic-gate mqp = queue_lock(mp, MX); 3766d4204c85Sraf enqueue(mqp, ulwp, 0); 37677c478bd9Sstevel@tonic-gate mp->mutex_waiters = 1; 37687c478bd9Sstevel@tonic-gate queue_unlock(mqp); 37697c478bd9Sstevel@tonic-gate queue_unlock(qp); 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate return (error); 37737c478bd9Sstevel@tonic-gate } 37747c478bd9Sstevel@tonic-gate 377541efec22Sraf /* 3776883492d5Sraf * Utility function called by mutex_wakeup_all(), cond_broadcast(), 3777883492d5Sraf * and rw_queue_release() to (re)allocate a big buffer to hold the 3778883492d5Sraf * lwpids of all the threads to be set running after they are removed 3779883492d5Sraf * from their sleep queues. Since we are holding a queue lock, we 3780883492d5Sraf * cannot call any function that might acquire a lock. mmap(), munmap(), 3781883492d5Sraf * lwp_unpark_all() are simple system calls and are safe in this regard. 378241efec22Sraf */ 378341efec22Sraf lwpid_t * 378441efec22Sraf alloc_lwpids(lwpid_t *lwpid, int *nlwpid_ptr, int *maxlwps_ptr) 378541efec22Sraf { 378641efec22Sraf /* 378741efec22Sraf * Allocate NEWLWPS ids on the first overflow. 378841efec22Sraf * Double the allocation each time after that. 378941efec22Sraf */ 379041efec22Sraf int nlwpid = *nlwpid_ptr; 379141efec22Sraf int maxlwps = *maxlwps_ptr; 379241efec22Sraf int first_allocation; 379341efec22Sraf int newlwps; 379441efec22Sraf void *vaddr; 379541efec22Sraf 379641efec22Sraf ASSERT(nlwpid == maxlwps); 379741efec22Sraf 379841efec22Sraf first_allocation = (maxlwps == MAXLWPS); 379941efec22Sraf newlwps = first_allocation? NEWLWPS : 2 * maxlwps; 38008cd45542Sraf vaddr = mmap(NULL, newlwps * sizeof (lwpid_t), 380141efec22Sraf PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, (off_t)0); 380241efec22Sraf 380341efec22Sraf if (vaddr == MAP_FAILED) { 380441efec22Sraf /* 380541efec22Sraf * Let's hope this never happens. 380641efec22Sraf * If it does, then we have a terrible 380741efec22Sraf * thundering herd on our hands. 380841efec22Sraf */ 380941efec22Sraf (void) __lwp_unpark_all(lwpid, nlwpid); 381041efec22Sraf *nlwpid_ptr = 0; 381141efec22Sraf } else { 38128cd45542Sraf (void) memcpy(vaddr, lwpid, maxlwps * sizeof (lwpid_t)); 381341efec22Sraf if (!first_allocation) 38148cd45542Sraf (void) munmap((caddr_t)lwpid, 381541efec22Sraf maxlwps * sizeof (lwpid_t)); 381641efec22Sraf lwpid = vaddr; 381741efec22Sraf *maxlwps_ptr = newlwps; 381841efec22Sraf } 381941efec22Sraf 382041efec22Sraf return (lwpid); 382141efec22Sraf } 38227c478bd9Sstevel@tonic-gate 38237257d1b4Sraf #pragma weak pthread_cond_broadcast = cond_broadcast 38247257d1b4Sraf #pragma weak _cond_broadcast = cond_broadcast 38257c478bd9Sstevel@tonic-gate int 38267257d1b4Sraf cond_broadcast(cond_t *cvp) 38277c478bd9Sstevel@tonic-gate { 38287c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 38297c478bd9Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 38307c478bd9Sstevel@tonic-gate tdb_cond_stats_t *csp = COND_STATS(cvp, udp); 38317c478bd9Sstevel@tonic-gate int error = 0; 38327c478bd9Sstevel@tonic-gate queue_head_t *qp; 3833d4204c85Sraf queue_root_t *qrp; 38347c478bd9Sstevel@tonic-gate mutex_t *mp; 38357c478bd9Sstevel@tonic-gate mutex_t *mp_cache = NULL; 383641efec22Sraf queue_head_t *mqp = NULL; 38377c478bd9Sstevel@tonic-gate ulwp_t *ulwp; 38387c478bd9Sstevel@tonic-gate int nlwpid = 0; 38397c478bd9Sstevel@tonic-gate int maxlwps = MAXLWPS; 384041efec22Sraf lwpid_t buffer[MAXLWPS]; 384141efec22Sraf lwpid_t *lwpid = buffer; 38427c478bd9Sstevel@tonic-gate 38437c478bd9Sstevel@tonic-gate if (csp) 38447c478bd9Sstevel@tonic-gate tdb_incr(csp->cond_broadcast); 38457c478bd9Sstevel@tonic-gate 38467c478bd9Sstevel@tonic-gate if (cvp->cond_waiters_kernel) /* someone sleeping in the kernel? */ 38477257d1b4Sraf error = _lwp_cond_broadcast(cvp); 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate if (!cvp->cond_waiters_user) /* no one sleeping at user-level */ 38507c478bd9Sstevel@tonic-gate return (error); 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate /* 38537c478bd9Sstevel@tonic-gate * Move everyone from the condvar sleep queue to the mutex sleep 38547c478bd9Sstevel@tonic-gate * queue for the mutex that they will acquire on being waked up. 38557c478bd9Sstevel@tonic-gate * We can do this only if we own the mutex they will acquire. 38567c478bd9Sstevel@tonic-gate * If we do not own the mutex, or if their ul_cv_wake flag 38577c478bd9Sstevel@tonic-gate * is set, just dequeue and unpark them. 38587c478bd9Sstevel@tonic-gate * 38597c478bd9Sstevel@tonic-gate * We keep track of lwpids that are to be unparked in lwpid[]. 38607c478bd9Sstevel@tonic-gate * __lwp_unpark_all() is called to unpark all of them after 38617c478bd9Sstevel@tonic-gate * they have been removed from the sleep queue and the sleep 38627c478bd9Sstevel@tonic-gate * queue lock has been dropped. If we run out of space in our 38637c478bd9Sstevel@tonic-gate * on-stack buffer, we need to allocate more but we can't call 38647c478bd9Sstevel@tonic-gate * lmalloc() because we are holding a queue lock when the overflow 38657c478bd9Sstevel@tonic-gate * occurs and lmalloc() acquires a lock. We can't use alloca() 386641efec22Sraf * either because the application may have allocated a small 386741efec22Sraf * stack and we don't want to overrun the stack. So we call 386841efec22Sraf * alloc_lwpids() to allocate a bigger buffer using the mmap() 38697c478bd9Sstevel@tonic-gate * system call directly since that path acquires no locks. 38707c478bd9Sstevel@tonic-gate */ 38717c478bd9Sstevel@tonic-gate qp = queue_lock(cvp, CV); 38727c478bd9Sstevel@tonic-gate cvp->cond_waiters_user = 0; 3873d4204c85Sraf for (;;) { 3874d4204c85Sraf if ((qrp = qp->qh_root) == NULL || 3875d4204c85Sraf (ulwp = qrp->qr_head) == NULL) 3876d4204c85Sraf break; 3877d4204c85Sraf ASSERT(ulwp->ul_wchan == cvp); 3878d4204c85Sraf queue_unlink(qp, &qrp->qr_head, NULL); 38797c478bd9Sstevel@tonic-gate mp = ulwp->ul_cvmutex; /* his mutex */ 38807c478bd9Sstevel@tonic-gate ulwp->ul_cvmutex = NULL; 38817c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 38827c478bd9Sstevel@tonic-gate if (ulwp->ul_cv_wake || !MUTEX_OWNED(mp, self)) { 3883d4204c85Sraf /* just wake him up */ 38847c478bd9Sstevel@tonic-gate ulwp->ul_sleepq = NULL; 38857c478bd9Sstevel@tonic-gate ulwp->ul_wchan = NULL; 388641efec22Sraf if (nlwpid == maxlwps) 388741efec22Sraf lwpid = alloc_lwpids(lwpid, &nlwpid, &maxlwps); 38887c478bd9Sstevel@tonic-gate lwpid[nlwpid++] = ulwp->ul_lwpid; 38897c478bd9Sstevel@tonic-gate } else { 3890d4204c85Sraf /* move him to the mutex queue */ 38917c478bd9Sstevel@tonic-gate if (mp != mp_cache) { 38927c478bd9Sstevel@tonic-gate mp_cache = mp; 389341efec22Sraf if (mqp != NULL) 389441efec22Sraf queue_unlock(mqp); 389541efec22Sraf mqp = queue_lock(mp, MX); 38967c478bd9Sstevel@tonic-gate } 3897d4204c85Sraf enqueue(mqp, ulwp, 0); 38987c478bd9Sstevel@tonic-gate mp->mutex_waiters = 1; 38997c478bd9Sstevel@tonic-gate } 39007c478bd9Sstevel@tonic-gate } 390141efec22Sraf if (mqp != NULL) 390241efec22Sraf queue_unlock(mqp); 390341efec22Sraf if (nlwpid == 0) { 39047c478bd9Sstevel@tonic-gate queue_unlock(qp); 390541efec22Sraf } else { 390641efec22Sraf no_preempt(self); 390741efec22Sraf queue_unlock(qp); 39087c478bd9Sstevel@tonic-gate if (nlwpid == 1) 39097c478bd9Sstevel@tonic-gate (void) __lwp_unpark(lwpid[0]); 39107c478bd9Sstevel@tonic-gate else 39117c478bd9Sstevel@tonic-gate (void) __lwp_unpark_all(lwpid, nlwpid); 391241efec22Sraf preempt(self); 39137c478bd9Sstevel@tonic-gate } 39147c478bd9Sstevel@tonic-gate if (lwpid != buffer) 39158cd45542Sraf (void) munmap((caddr_t)lwpid, maxlwps * sizeof (lwpid_t)); 39167c478bd9Sstevel@tonic-gate return (error); 39177c478bd9Sstevel@tonic-gate } 39187c478bd9Sstevel@tonic-gate 39197257d1b4Sraf #pragma weak pthread_cond_destroy = cond_destroy 39207c478bd9Sstevel@tonic-gate int 39217257d1b4Sraf cond_destroy(cond_t *cvp) 39227c478bd9Sstevel@tonic-gate { 39237c478bd9Sstevel@tonic-gate cvp->cond_magic = 0; 39247c478bd9Sstevel@tonic-gate tdb_sync_obj_deregister(cvp); 39257c478bd9Sstevel@tonic-gate return (0); 39267c478bd9Sstevel@tonic-gate } 39277c478bd9Sstevel@tonic-gate 39287c478bd9Sstevel@tonic-gate #if defined(THREAD_DEBUG) 39297c478bd9Sstevel@tonic-gate void 39307c478bd9Sstevel@tonic-gate assert_no_libc_locks_held(void) 39317c478bd9Sstevel@tonic-gate { 39327c478bd9Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 39337c478bd9Sstevel@tonic-gate } 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate /* protected by link_lock */ 39367c478bd9Sstevel@tonic-gate uint64_t spin_lock_spin; 39377c478bd9Sstevel@tonic-gate uint64_t spin_lock_spin2; 39387c478bd9Sstevel@tonic-gate uint64_t spin_lock_sleep; 39397c478bd9Sstevel@tonic-gate uint64_t spin_lock_wakeup; 39407c478bd9Sstevel@tonic-gate 39417c478bd9Sstevel@tonic-gate /* 39427c478bd9Sstevel@tonic-gate * Record spin lock statistics. 39437c478bd9Sstevel@tonic-gate * Called by a thread exiting itself in thrp_exit(). 39447c478bd9Sstevel@tonic-gate * Also called via atexit() from the thread calling 39457c478bd9Sstevel@tonic-gate * exit() to do all the other threads as well. 39467c478bd9Sstevel@tonic-gate */ 39477c478bd9Sstevel@tonic-gate void 39487c478bd9Sstevel@tonic-gate record_spin_locks(ulwp_t *ulwp) 39497c478bd9Sstevel@tonic-gate { 39507c478bd9Sstevel@tonic-gate spin_lock_spin += ulwp->ul_spin_lock_spin; 39517c478bd9Sstevel@tonic-gate spin_lock_spin2 += ulwp->ul_spin_lock_spin2; 39527c478bd9Sstevel@tonic-gate spin_lock_sleep += ulwp->ul_spin_lock_sleep; 39537c478bd9Sstevel@tonic-gate spin_lock_wakeup += ulwp->ul_spin_lock_wakeup; 39547c478bd9Sstevel@tonic-gate ulwp->ul_spin_lock_spin = 0; 39557c478bd9Sstevel@tonic-gate ulwp->ul_spin_lock_spin2 = 0; 39567c478bd9Sstevel@tonic-gate ulwp->ul_spin_lock_sleep = 0; 39577c478bd9Sstevel@tonic-gate ulwp->ul_spin_lock_wakeup = 0; 39587c478bd9Sstevel@tonic-gate } 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate /* 39617c478bd9Sstevel@tonic-gate * atexit function: dump the queue statistics to stderr. 39627c478bd9Sstevel@tonic-gate */ 39637c478bd9Sstevel@tonic-gate #include <stdio.h> 39647c478bd9Sstevel@tonic-gate void 39657c478bd9Sstevel@tonic-gate dump_queue_statistics(void) 39667c478bd9Sstevel@tonic-gate { 39677c478bd9Sstevel@tonic-gate uberdata_t *udp = curthread->ul_uberdata; 39687c478bd9Sstevel@tonic-gate queue_head_t *qp; 39697c478bd9Sstevel@tonic-gate int qn; 39707c478bd9Sstevel@tonic-gate uint64_t spin_lock_total = 0; 39717c478bd9Sstevel@tonic-gate 39727c478bd9Sstevel@tonic-gate if (udp->queue_head == NULL || thread_queue_dump == 0) 39737c478bd9Sstevel@tonic-gate return; 39747c478bd9Sstevel@tonic-gate 39757c478bd9Sstevel@tonic-gate if (fprintf(stderr, "\n%5d mutex queues:\n", QHASHSIZE) < 0 || 3976d4204c85Sraf fprintf(stderr, "queue# lockcount max qlen max hlen\n") < 0) 39777c478bd9Sstevel@tonic-gate return; 39787c478bd9Sstevel@tonic-gate for (qn = 0, qp = udp->queue_head; qn < QHASHSIZE; qn++, qp++) { 39797c478bd9Sstevel@tonic-gate if (qp->qh_lockcount == 0) 39807c478bd9Sstevel@tonic-gate continue; 39817c478bd9Sstevel@tonic-gate spin_lock_total += qp->qh_lockcount; 3982d4204c85Sraf if (fprintf(stderr, "%5d %12llu%12u%12u\n", qn, 3983d4204c85Sraf (u_longlong_t)qp->qh_lockcount, 3984d4204c85Sraf qp->qh_qmax, qp->qh_hmax) < 0) 39857c478bd9Sstevel@tonic-gate return; 39867c478bd9Sstevel@tonic-gate } 39877c478bd9Sstevel@tonic-gate 39887c478bd9Sstevel@tonic-gate if (fprintf(stderr, "\n%5d condvar queues:\n", QHASHSIZE) < 0 || 3989d4204c85Sraf fprintf(stderr, "queue# lockcount max qlen max hlen\n") < 0) 39907c478bd9Sstevel@tonic-gate return; 39917c478bd9Sstevel@tonic-gate for (qn = 0; qn < QHASHSIZE; qn++, qp++) { 39927c478bd9Sstevel@tonic-gate if (qp->qh_lockcount == 0) 39937c478bd9Sstevel@tonic-gate continue; 39947c478bd9Sstevel@tonic-gate spin_lock_total += qp->qh_lockcount; 3995d4204c85Sraf if (fprintf(stderr, "%5d %12llu%12u%12u\n", qn, 3996d4204c85Sraf (u_longlong_t)qp->qh_lockcount, 3997d4204c85Sraf qp->qh_qmax, qp->qh_hmax) < 0) 39987c478bd9Sstevel@tonic-gate return; 39997c478bd9Sstevel@tonic-gate } 40007c478bd9Sstevel@tonic-gate 40017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n spin_lock_total = %10llu\n", 40027c478bd9Sstevel@tonic-gate (u_longlong_t)spin_lock_total); 40037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " spin_lock_spin = %10llu\n", 40047c478bd9Sstevel@tonic-gate (u_longlong_t)spin_lock_spin); 40057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " spin_lock_spin2 = %10llu\n", 40067c478bd9Sstevel@tonic-gate (u_longlong_t)spin_lock_spin2); 40077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " spin_lock_sleep = %10llu\n", 40087c478bd9Sstevel@tonic-gate (u_longlong_t)spin_lock_sleep); 40097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " spin_lock_wakeup = %10llu\n", 40107c478bd9Sstevel@tonic-gate (u_longlong_t)spin_lock_wakeup); 40117c478bd9Sstevel@tonic-gate } 4012d4204c85Sraf #endif 4013