rwlock.c revision d4204c85a44d2589b9afff2c81db7044e97f2d1d
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * CDDL HEADER START
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw *
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * The contents of this file are subject to the terms of the
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Common Development and Distribution License (the "License").
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * You may not use this file except in compliance with the License.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw *
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * or http://www.opensolaris.org/os/licensing.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * See the License for the specific language governing permissions
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * and limitations under the License.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw *
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * When distributing Covered Code, include this CDDL HEADER in each
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If applicable, add the following below this CDDL HEADER, with the
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * fields enclosed by brackets "[]" replaced with your own identifying
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * information: Portions Copyright [yyyy] [name of copyright owner]
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw *
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * CDDL HEADER END
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Use is subject to license terms.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma ident "%Z%%M% %I% %E% SMI"
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#include "lint.h"
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#include "thr_uberdata.h"
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#include <sys/sdt.h>
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define TRY_FLAG 0x10
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define READ_LOCK 0
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define WRITE_LOCK 1
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define READ_LOCK_TRY (READ_LOCK | TRY_FLAG)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define WRITE_LOCK_TRY (WRITE_LOCK | TRY_FLAG)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define NLOCKS 4 /* initial number of readlock_t structs allocated */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#define ASSERT_CONSISTENT_STATE(readers) \
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!((readers) & URW_WRITE_LOCKED) || \
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ((readers) & ~URW_HAS_WAITERS) == URW_WRITE_LOCKED)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Find/allocate an entry for rwlp in our array of rwlocks held for reading.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * We must be deferring signals for this to be safe.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Else if we are returning an entry with ul_rdlockcnt == 0,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * it could be reassigned behind our back in a signal handler.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwstatic readlock_t *
bda89588bd7667394a834e8a9a34612cce2ae9c3jprwl_entry(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlock_t *remembered = NULL;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlock_t *readlockp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uint_t nlocks;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* we must be deferring signals */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT((self->ul_critical + self->ul_sigdefer) != 0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if ((nlocks = self->ul_rdlockcnt) != 0)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readlockp = self->ul_readlock.array;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp else {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp nlocks = 1;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlockp = &self->ul_readlock.single;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw for (; nlocks; nlocks--, readlockp++) {
0b10de9fc92843e871f48de87f623808c5913a71jp if (readlockp->rd_rwlock == rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (readlockp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_count == 0 && remembered == NULL)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw remembered = readlockp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (remembered != NULL) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw remembered->rd_rwlock = rwlp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (remembered);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * No entry available. Allocate more space, converting the single
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * readlock_t entry into an array of readlock_t entries if necessary.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if ((nlocks = self->ul_rdlockcnt) == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Initial allocation of the readlock_t array.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Convert the single entry into an array.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp self->ul_rdlockcnt = nlocks = NLOCKS;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readlockp = lmalloc(nlocks * sizeof (readlock_t));
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * The single readlock_t becomes the first entry in the array.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp *readlockp = self->ul_readlock.single;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp self->ul_readlock.single.rd_count = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw self->ul_readlock.array = readlockp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Return the next available entry in the array.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp (++readlockp)->rd_rwlock = rwlp;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (readlockp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Reallocate the array, double the size each time.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlockp = lmalloc(nlocks * 2 * sizeof (readlock_t));
bda89588bd7667394a834e8a9a34612cce2ae9c3jp (void) _memcpy(readlockp, self->ul_readlock.array,
bda89588bd7667394a834e8a9a34612cce2ae9c3jp nlocks * sizeof (readlock_t));
bda89588bd7667394a834e8a9a34612cce2ae9c3jp lfree(self->ul_readlock.array, nlocks * sizeof (readlock_t));
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw self->ul_readlock.array = readlockp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw self->ul_rdlockcnt *= 2;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Return the next available entry in the newly allocated array.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp (readlockp += nlocks)->rd_rwlock = rwlp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (readlockp);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Free the array of rwlocks held for reading.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwvoid
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwrwl_free(ulwp_t *ulwp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uint_t nlocks;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if ((nlocks = ulwp->ul_rdlockcnt) != 0)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp lfree(ulwp->ul_readlock.array, nlocks * sizeof (readlock_t));
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp->ul_rdlockcnt = 0;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ulwp->ul_readlock.single.rd_rwlock = NULL;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp->ul_readlock.single.rd_count = 0;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
bda89588bd7667394a834e8a9a34612cce2ae9c3jp/*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Check if a reader version of the lock is held by the current thread.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * rw_read_is_held() is private to libc.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp#pragma weak rw_read_is_held = _rw_read_held
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak rw_read_held = _rw_read_held
bda89588bd7667394a834e8a9a34612cce2ae9c3jpint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw_rw_read_held(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uint32_t readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ulwp_t *self = curthread;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readlock_t *readlockp;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uint_t nlocks;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp int rval = 0;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp no_preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readers = *rwstate;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT_CONSISTENT_STATE(readers);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (!(readers & URW_WRITE_LOCKED) &&
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (readers & URW_READERS_MASK) != 0) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * The lock is held for reading by some thread.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Search our array of rwlocks held for reading for a match.
0b10de9fc92843e871f48de87f623808c5913a71jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if ((nlocks = self->ul_rdlockcnt) != 0)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readlockp = self->ul_readlock.array;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp else {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp nlocks = 1;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp readlockp = &self->ul_readlock.single;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw for (; nlocks; nlocks--, readlockp++) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_rwlock == rwlp) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (readlockp->rd_count)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp rval = 1;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp break;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw preempt(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (rval);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp/*
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * Check if a writer version of the lock is held by the current thread.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * rw_write_is_held() is private to libc.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp */
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak rw_write_is_held = _rw_write_held
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak rw_write_held = _rw_write_held
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jpint
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp_rw_write_held(rwlock_t *rwlp)
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp{
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp uint32_t readers;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp ulwp_t *self = curthread;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp int rval;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp no_preempt(self);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readers = *rwstate;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ASSERT_CONSISTENT_STATE(readers);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rval = ((readers & URW_WRITE_LOCKED) &&
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->rwlock_owner == (uintptr_t)self &&
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp (rwlp->rwlock_type == USYNC_THREAD ||
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->rwlock_ownerpid == self->ul_uberdata->pid));
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw preempt(self);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp return (rval);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp}
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak rwlock_init = __rwlock_init
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak _rwlock_init = __rwlock_init
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp/* ARGSUSED2 */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
bda89588bd7667394a834e8a9a34612cce2ae9c3jp__rwlock_init(rwlock_t *rwlp, int type, void *arg)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp if (type != USYNC_THREAD && type != USYNC_PROCESS)
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp return (EINVAL);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp /*
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * Once reinitialized, we can no longer be holding a read or write lock.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * We can do nothing about other threads that are holding read locks.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp */
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp sigoff(curthread);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwl_entry(rwlp)->rd_count = 0;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp sigon(curthread);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) _memset(rwlp, 0, sizeof (*rwlp));
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->rwlock_type = (uint16_t)type;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->rwlock_magic = RWL_MAGIC;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->mutex.mutex_type = (uint8_t)type;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->mutex.mutex_flag = LOCK_INITED;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwlp->mutex.mutex_magic = MUTEX_MAGIC;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp return (0);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
323a81d93e2f58a7d62f6e523f9fddbc029d3d0bjwadams
bda89588bd7667394a834e8a9a34612cce2ae9c3jp#pragma weak rwlock_destroy = __rwlock_destroy
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak _rwlock_destroy = __rwlock_destroy
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak pthread_rwlock_destroy = __rwlock_destroy
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp#pragma weak _pthread_rwlock_destroy = __rwlock_destroy
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jpint
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp__rwlock_destroy(rwlock_t *rwlp)
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp{
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp /*
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * Once destroyed, we can no longer be holding a read or write lock.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * We can do nothing about other threads that are holding read locks.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp */
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp sigoff(curthread);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp rwl_entry(rwlp)->rd_count = 0;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp sigon(curthread);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp rwlp->rwlock_magic = 0;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp tdb_sync_obj_deregister(rwlp);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (0);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp}
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp/*
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * Attempt to acquire a readers lock. Return true on success.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp */
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jpstatic int
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jpread_lock_try(rwlock_t *rwlp, int ignore_waiters_flag)
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp{
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp uint32_t mask = ignore_waiters_flag?
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp URW_WRITE_LOCKED : (URW_HAS_WAITERS | URW_WRITE_LOCKED);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp uint32_t readers;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp ulwp_t *self = curthread;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp no_preempt(self);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp while (((readers = *rwstate) & mask) == 0) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (atomic_cas_32(rwstate, readers, readers + 1) == readers) {
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (1);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp preempt(self);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp return (0);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp}
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp/*
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp * Attempt to release a reader lock. Return true on success.
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp */
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jpstatic int
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwread_unlock_try(rwlock_t *rwlp)
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp{
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp uint32_t readers;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp ulwp_t *self = curthread;
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp no_preempt(self);
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp while (((readers = *rwstate) & URW_HAS_WAITERS) == 0) {
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp if (atomic_cas_32(rwstate, readers, readers - 1) == readers) {
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp preempt(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (1);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp/*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Attempt to acquire a writer lock. Return true on success.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jpstatic int
bda89588bd7667394a834e8a9a34612cce2ae9c3jpwrite_lock_try(rwlock_t *rwlp, int ignore_waiters_flag)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp{
bda89588bd7667394a834e8a9a34612cce2ae9c3jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uint32_t mask = ignore_waiters_flag?
bda89588bd7667394a834e8a9a34612cce2ae9c3jp (URW_WRITE_LOCKED | URW_READERS_MASK) :
bda89588bd7667394a834e8a9a34612cce2ae9c3jp (URW_HAS_WAITERS | URW_WRITE_LOCKED | URW_READERS_MASK);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ulwp_t *self = curthread;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uint32_t readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
f7b4b2fefbe31d31fbe1e6a4b494a8fbed3f49b1jp no_preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp while (((readers = *rwstate) & mask) == 0) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (atomic_cas_32(rwstate, readers, readers | URW_WRITE_LOCKED)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp == readers) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (1);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp/*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * Attempt to release a writer lock. Return true on success.
bda89588bd7667394a834e8a9a34612cce2ae9c3jp */
bda89588bd7667394a834e8a9a34612cce2ae9c3jpstatic int
bda89588bd7667394a834e8a9a34612cce2ae9c3jpwrite_unlock_try(rwlock_t *rwlp)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp{
bda89588bd7667394a834e8a9a34612cce2ae9c3jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uint32_t readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ulwp_t *self = curthread;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp no_preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp while (((readers = *rwstate) & URW_HAS_WAITERS) == 0) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (atomic_cas_32(rwstate, readers, 0) == readers) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (1);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw preempt(self);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Wake up thread(s) sleeping on the rwlock queue and then
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * drop the queue lock. Return non-zero if we wake up someone.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * This is called when a thread releases a lock that appears to have waiters.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwstatic int
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwrw_queue_release(queue_head_t *qp, rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
bda89588bd7667394a834e8a9a34612cce2ae9c3jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uint32_t readers;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uint32_t writers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t **ulwpp;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ulwp_t *ulwp;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ulwp_t *prev;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp int nlwpid = 0;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp int more;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp int maxlwps = MAXLWPS;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp lwpid_t buffer[MAXLWPS];
bda89588bd7667394a834e8a9a34612cce2ae9c3jp lwpid_t *lwpid = buffer;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readers = *rwstate;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ASSERT_CONSISTENT_STATE(readers);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (!(readers & URW_HAS_WAITERS)) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp queue_unlock(qp);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp readers &= URW_READERS_MASK;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp writers = 0;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Examine the queue of waiters in priority order and prepare
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * to wake up as many readers as we encounter before encountering
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * a writer. If the highest priority thread on the queue is a
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * writer, stop there and wake it up.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw *
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * We keep track of lwpids that are to be unparked in lwpid[].
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * __lwp_unpark_all() is called to unpark all of them after
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * they have been removed from the sleep queue and the sleep
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * queue lock has been dropped. If we run out of space in our
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * on-stack buffer, we need to allocate more but we can't call
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * lmalloc() because we are holding a queue lock when the overflow
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * occurs and lmalloc() acquires a lock. We can't use alloca()
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * either because the application may have allocated a small
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * stack and we don't want to overrun the stack. So we call
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * alloc_lwpids() to allocate a bigger buffer using the mmap()
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * system call directly since that path acquires no locks.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp while ((ulwpp = queue_slot(qp, &prev, &more)) != NULL) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp = *ulwpp;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ASSERT(ulwp->ul_wchan == rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (ulwp->ul_writer) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (writers != 0 || readers != 0)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /* one writer to wake */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp writers++;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (writers != 0)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* at least one reader to wake */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readers++;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (nlwpid == maxlwps)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw lwpid = alloc_lwpids(lwpid, &nlwpid, &maxlwps);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_unlink(qp, ulwpp, prev);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp->ul_sleepq = NULL;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp->ul_wchan = NULL;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw lwpid[nlwpid++] = ulwp->ul_lwpid;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (ulwpp == NULL)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp atomic_and_32(rwstate, ~URW_HAS_WAITERS);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (nlwpid == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_unlock(qp);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw no_preempt(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_unlock(qp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (nlwpid == 1)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) __lwp_unpark(lwpid[0]);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) __lwp_unpark_all(lwpid, nlwpid);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw preempt(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (lwpid != buffer)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp (void) _private_munmap(lwpid, maxlwps * sizeof (lwpid_t));
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (nlwpid != 0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
0b10de9fc92843e871f48de87f623808c5913a71jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Common code for rdlock, timedrdlock, wrlock, timedwrlock, tryrdlock,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * and trywrlock for process-shared (USYNC_PROCESS) rwlocks.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw *
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Note: if the lock appears to be contended we call __lwp_rwlock_rdlock()
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * or __lwp_rwlock_wrlock() holding the mutex. These return with the mutex
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * released, and if they need to sleep will release the mutex first. In the
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * event of a spurious wakeup, these will return EAGAIN (because it is much
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * easier for us to re-acquire the mutex here).
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwshared_rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
bda89588bd7667394a834e8a9a34612cce2ae9c3jp volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw mutex_t *mp = &rwlp->mutex;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uint32_t readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int try_flag;
9d0aba9223380be5042b63aef9767fa367b2a2ecjp int error;
9d0aba9223380be5042b63aef9767fa367b2a2ecjp
9d0aba9223380be5042b63aef9767fa367b2a2ecjp try_flag = (rd_wr & TRY_FLAG);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp rd_wr &= ~TRY_FLAG;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(rd_wr == READ_LOCK || rd_wr == WRITE_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (!try_flag) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE2(plockstat, rw__block, rwlp, rd_wr);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp do {
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp if (try_flag && (*rwstate & URW_WRITE_LOCKED)) {
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp error = EBUSY;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if ((error = _private_mutex_lock(mp)) != 0)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rd_wr == READ_LOCK) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (read_lock_try(rwlp, 0)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) _private_mutex_unlock(mp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (write_lock_try(rwlp, 0)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) _private_mutex_unlock(mp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw atomic_or_32(rwstate, URW_HAS_WAITERS);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readers = *rwstate;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT_CONSISTENT_STATE(readers);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * The calls to __lwp_rwlock_*() below will release the mutex,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * so we need a dtrace probe here.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw mp->mutex_owner = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE2(plockstat, mutex__release, mp, 0);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * The waiters bit may be inaccurate.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Only the kernel knows for sure.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rd_wr == READ_LOCK) {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (try_flag)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = __lwp_rwlock_tryrdlock(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = __lwp_rwlock_rdlock(rwlp, tsp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (try_flag)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = __lwp_rwlock_trywrlock(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = __lwp_rwlock_wrlock(rwlp, tsp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } while (error == EAGAIN || error == EINTR);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (!try_flag) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, error == 0);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (error);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw/*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Common code for rdlock, timedrdlock, wrlock, timedwrlock, tryrdlock,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * and trywrlock for process-private (USYNC_THREAD) rwlocks.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwrwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uint32_t readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_head_t *qp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *ulwp;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp int try_flag;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int ignore_waiters_flag;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
9d0aba9223380be5042b63aef9767fa367b2a2ecjp try_flag = (rd_wr & TRY_FLAG);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp rd_wr &= ~TRY_FLAG;
9d0aba9223380be5042b63aef9767fa367b2a2ecjp ASSERT(rd_wr == READ_LOCK || rd_wr == WRITE_LOCK);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (!try_flag) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE2(plockstat, rw__block, rwlp, rd_wr);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw qp = queue_lock(rwlp, MX);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* initial attempt to acquire the lock fails if there are waiters */
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp ignore_waiters_flag = 0;
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp while (error == 0) {
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp if (rd_wr == READ_LOCK) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (read_lock_try(rwlp, ignore_waiters_flag))
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (write_lock_try(rwlp, ignore_waiters_flag))
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* subsequent attempts do not fail due to waiters */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ignore_waiters_flag = 1;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw atomic_or_32(rwstate, URW_HAS_WAITERS);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readers = *rwstate;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT_CONSISTENT_STATE(readers);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if ((readers & URW_WRITE_LOCKED) ||
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (rd_wr == WRITE_LOCK &&
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (readers & URW_READERS_MASK) != 0))
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* EMPTY */; /* somebody holds the lock */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else if ((ulwp = queue_waiter(qp)) == NULL) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw atomic_and_32(rwstate, ~URW_HAS_WAITERS);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw continue; /* no queued waiters, try again */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Do a priority check on the queued waiter (the
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * highest priority thread on the queue) to see
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * if we should defer to him or just grab the lock.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int our_pri = real_priority(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int his_pri = real_priority(ulwp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rd_wr == WRITE_LOCK) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * We defer to a queued thread that has
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * a higher priority than ours.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (his_pri <= our_pri)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw continue; /* try again */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * We defer to a queued thread that has
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * a higher priority than ours or that
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * is a writer whose priority equals ours.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (his_pri < our_pri ||
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (his_pri == our_pri && !ulwp->ul_writer))
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw continue; /* try again */
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp /*
bda89588bd7667394a834e8a9a34612cce2ae9c3jp * We are about to block.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we're doing a trylock, return EBUSY instead.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (try_flag) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = EBUSY;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw break;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Enqueue writers ahead of readers.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw self->ul_writer = rd_wr; /* *must* be 0 or 1 */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw enqueue(qp, self, 0);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw set_parking_flag(self, 1);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_unlock(qp);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if ((error = __lwp_park(tsp, 0)) == EINTR)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = ignore_waiters_flag = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw set_parking_flag(self, 0);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw qp = queue_lock(rwlp, MX);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp if (self->ul_sleepq && dequeue_self(qp) == 0)
9d0aba9223380be5042b63aef9767fa367b2a2ecjp atomic_and_32(rwstate, ~URW_HAS_WAITERS);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp self->ul_writer = 0;
9d0aba9223380be5042b63aef9767fa367b2a2ecjp }
9d0aba9223380be5042b63aef9767fa367b2a2ecjp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_unlock(qp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (!try_flag) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, error == 0);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwrw_rdlock_impl(rwlock_t *rwlp, timespec_t *tsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp uberdata_t *udp = self->ul_uberdata;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlock_t *readlockp;
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp tdb_rwlock_stats_t *rwsp = RWLOCK_STATS(rwlp, udp);
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we already hold a readers lock on this rwlock,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * just increment our reference count and return.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigoff(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlockp = rwl_entry(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_count != 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_count == READ_LOCK_MAX) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = EAGAIN;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we hold the writer lock, bail out.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rw_write_is_held(rwlp)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (self->ul_error_detection)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlock_error(rwlp, "rwlock_rdlock",
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "calling thread owns the writer lock");
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = EDEADLK;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (read_lock_try(rwlp, 0))
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = 0;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = shared_rwlock_lock(rwlp, tsp, READ_LOCK);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp else /* user-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rwlock_lock(rwlp, tsp, READ_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwout:
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigoff(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwl_entry(rwlp)->rd_count++;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_incr(rwsp->rw_rdlock);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE2(plockstat, rw__acquire, rwlp, READ_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp DTRACE_PROBE3(plockstat, rw__error, rwlp, READ_LOCK, error);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak rw_rdlock = __rw_rdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _rw_rdlock = __rw_rdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_rdlock = __rw_rdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _pthread_rwlock_rdlock = __rw_rdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw__rw_rdlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (rw_rdlock_impl(rwlp, NULL));
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
bda89588bd7667394a834e8a9a34612cce2ae9c3jpvoid
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwlrw_rdlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw enter_critical(curthread);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp (void) rw_rdlock_impl(rwlp, NULL);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp}
9d0aba9223380be5042b63aef9767fa367b2a2ecjp
9d0aba9223380be5042b63aef9767fa367b2a2ecjp#pragma weak pthread_rwlock_reltimedrdlock_np = \
9d0aba9223380be5042b63aef9767fa367b2a2ecjp _pthread_rwlock_reltimedrdlock_np
cd37da7426f0c49c14ad9a8a07638ca971477566nwint
cd37da7426f0c49c14ad9a8a07638ca971477566nw_pthread_rwlock_reltimedrdlock_np(rwlock_t *rwlp, const timespec_t *reltime)
cd37da7426f0c49c14ad9a8a07638ca971477566nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw timespec_t tslocal = *reltime;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rw_rdlock_impl(rwlp, &tslocal);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == ETIME)
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp error = ETIMEDOUT;
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp return (error);
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_timedrdlock = _pthread_rwlock_timedrdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw_pthread_rwlock_timedrdlock(rwlock_t *rwlp, const timespec_t *abstime)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw timespec_t tslocal;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw abstime_to_reltime(CLOCK_REALTIME, abstime, &tslocal);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rw_rdlock_impl(rwlp, &tslocal);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == ETIME)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = ETIMEDOUT;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwrw_wrlock_impl(rwlock_t *rwlp, timespec_t *tsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uberdata_t *udp = self->ul_uberdata;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_rwlock_stats_t *rwsp = RWLOCK_STATS(rwlp, udp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we hold a readers lock on this rwlock, bail out.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rw_read_is_held(rwlp)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (self->ul_error_detection)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlock_error(rwlp, "rwlock_wrlock",
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "calling thread owns the readers lock");
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = EDEADLK;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we hold the writer lock, bail out.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rw_write_is_held(rwlp)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (self->ul_error_detection)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlock_error(rwlp, "rwlock_wrlock",
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "calling thread owns the writer lock");
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = EDEADLK;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (write_lock_try(rwlp, 0))
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = shared_rwlock_lock(rwlp, tsp, WRITE_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else /* user-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rwlock_lock(rwlp, tsp, WRITE_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwout:
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlp->rwlock_owner = (uintptr_t)self;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwlp->rwlock_type == USYNC_PROCESS)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlp->rwlock_ownerpid = udp->pid;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_incr(rwsp->rw_wrlock);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwsp->rw_wrlock_begin_hold = gethrtime();
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp DTRACE_PROBE2(plockstat, rw__acquire, rwlp, WRITE_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE3(plockstat, rw__error, rwlp, WRITE_LOCK, error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
9d0aba9223380be5042b63aef9767fa367b2a2ecjp return (error);
9d0aba9223380be5042b63aef9767fa367b2a2ecjp}
9d0aba9223380be5042b63aef9767fa367b2a2ecjp
9d0aba9223380be5042b63aef9767fa367b2a2ecjp#pragma weak rw_wrlock = __rw_wrlock
9d0aba9223380be5042b63aef9767fa367b2a2ecjp#pragma weak _rw_wrlock = __rw_wrlock
cd37da7426f0c49c14ad9a8a07638ca971477566nw#pragma weak pthread_rwlock_wrlock = __rw_wrlock
cd37da7426f0c49c14ad9a8a07638ca971477566nw#pragma weak _pthread_rwlock_wrlock = __rw_wrlock
cd37da7426f0c49c14ad9a8a07638ca971477566nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw__rw_wrlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (rw_wrlock_impl(rwlp, NULL));
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
d15447b6c777a1b2223924443bf36c9c8efb2ea4jpvoid
d15447b6c777a1b2223924443bf36c9c8efb2ea4jplrw_wrlock(rwlock_t *rwlp)
d15447b6c777a1b2223924443bf36c9c8efb2ea4jp{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw enter_critical(curthread);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) rw_wrlock_impl(rwlp, NULL);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_reltimedwrlock_np = \
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw _pthread_rwlock_reltimedwrlock_np
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw_pthread_rwlock_reltimedwrlock_np(rwlock_t *rwlp, const timespec_t *reltime)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw timespec_t tslocal = *reltime;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rw_wrlock_impl(rwlp, &tslocal);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == ETIME)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = ETIMEDOUT;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_timedwrlock = _pthread_rwlock_timedwrlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw_pthread_rwlock_timedwrlock(rwlock_t *rwlp, const timespec_t *abstime)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw timespec_t tslocal;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
bda89588bd7667394a834e8a9a34612cce2ae9c3jp ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw abstime_to_reltime(CLOCK_REALTIME, abstime, &tslocal);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = rw_wrlock_impl(rwlp, &tslocal);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (error == ETIME)
bda89588bd7667394a834e8a9a34612cce2ae9c3jp error = ETIMEDOUT;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp return (error);
bda89588bd7667394a834e8a9a34612cce2ae9c3jp}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak rw_tryrdlock = __rw_tryrdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _rw_tryrdlock = __rw_tryrdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_tryrdlock = __rw_tryrdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _pthread_rwlock_tryrdlock = __rw_tryrdlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw__rw_tryrdlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uberdata_t *udp = self->ul_uberdata;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_rwlock_stats_t *rwsp = RWLOCK_STATS(rwlp, udp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlock_t *readlockp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!curthread->ul_critical || curthread->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_incr(rwsp->rw_rdlock_try);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we already hold a readers lock on this rwlock,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * just increment our reference count and return.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigoff(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlockp = rwl_entry(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_count != 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_count == READ_LOCK_MAX) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = EAGAIN;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (read_lock_try(rwlp, 0))
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = shared_rwlock_lock(rwlp, NULL, READ_LOCK_TRY);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else /* user-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rwlock_lock(rwlp, NULL, READ_LOCK_TRY);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwout:
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigoff(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwl_entry(rwlp)->rd_count++;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE2(plockstat, rw__acquire, rwlp, READ_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_incr(rwsp->rw_rdlock_try_fail);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error != EBUSY) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE3(plockstat, rw__error, rwlp, READ_LOCK,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak rw_trywrlock = __rw_trywrlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _rw_trywrlock = __rw_trywrlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_trywrlock = __rw_trywrlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _pthread_rwlock_trywrlock = __rw_trywrlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw__rw_trywrlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
bda89588bd7667394a834e8a9a34612cce2ae9c3jp uberdata_t *udp = self->ul_uberdata;
0b10de9fc92843e871f48de87f623808c5913a71jp tdb_rwlock_stats_t *rwsp = RWLOCK_STATS(rwlp, udp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int error;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT(!self->ul_critical || self->ul_bindflags);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_incr(rwsp->rw_wrlock_try);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (write_lock_try(rwlp, 0))
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = shared_rwlock_lock(rwlp, NULL, WRITE_LOCK_TRY);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else /* user-level */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error = rwlock_lock(rwlp, NULL, WRITE_LOCK_TRY);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlp->rwlock_owner = (uintptr_t)self;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwlp->rwlock_type == USYNC_PROCESS)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlp->rwlock_ownerpid = udp->pid;
0b10de9fc92843e871f48de87f623808c5913a71jp if (rwsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwsp->rw_wrlock_begin_hold = gethrtime();
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE2(plockstat, rw__acquire, rwlp, WRITE_LOCK);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_incr(rwsp->rw_wrlock_try_fail);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (error != EBUSY) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw DTRACE_PROBE3(plockstat, rw__error, rwlp, WRITE_LOCK,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (error);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak rw_unlock = __rw_unlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _rw_unlock = __rw_unlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak pthread_rwlock_unlock = __rw_unlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw#pragma weak _pthread_rwlock_unlock = __rw_unlock
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwint
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw__rw_unlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uint32_t readers;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ulwp_t *self = curthread;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw uberdata_t *udp = self->ul_uberdata;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw tdb_rwlock_stats_t *rwsp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw queue_head_t *qp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int rd_wr;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw int waked = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readers = *rwstate;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw ASSERT_CONSISTENT_STATE(readers);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readers & URW_WRITE_LOCKED) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rd_wr = WRITE_LOCK;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readers = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
bda89588bd7667394a834e8a9a34612cce2ae9c3jp rd_wr = READ_LOCK;
0b10de9fc92843e871f48de87f623808c5913a71jp readers &= URW_READERS_MASK;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rd_wr == WRITE_LOCK) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Since the writer lock is held, we'd better be
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * holding it, else we cannot legitimately be here.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (!rw_write_is_held(rwlp)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (self->ul_error_detection)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlock_error(rwlp, "rwlock_unlock",
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "writer lock held, "
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "but not by the calling thread");
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (EPERM);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if ((rwsp = RWLOCK_STATS(rwlp, udp)) != NULL) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rwsp->rw_wrlock_begin_hold)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwsp->rw_wrlock_hold_time +=
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw gethrtime() - rwsp->rw_wrlock_begin_hold;
0b10de9fc92843e871f48de87f623808c5913a71jp rwsp->rw_wrlock_begin_hold = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlp->rwlock_owner = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlp->rwlock_ownerpid = 0;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else if (readers > 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * A readers lock is held; if we don't hold one, bail out.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlock_t *readlockp;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigoff(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw readlockp = rwl_entry(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (readlockp->rd_count == 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (self->ul_error_detection)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlock_error(rwlp, "rwlock_unlock",
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "readers lock held, "
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw "but not by the calling thread");
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (EPERM);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * If we hold more than one readers lock on this rwlock,
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * just decrement our reference count and return.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (--readlockp->rd_count != 0) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw goto out;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw sigon(self);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * This is a usage error.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * No thread should release an unowned lock.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (self->ul_error_detection)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw rwlock_error(rwlp, "rwlock_unlock", "lock not owned");
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (EPERM);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
bda89588bd7667394a834e8a9a34612cce2ae9c3jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rd_wr == WRITE_LOCK && write_unlock_try(rwlp)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* EMPTY */;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else if (rd_wr == READ_LOCK && read_unlock_try(rwlp)) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /* EMPTY */;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else if (rwlp->rwlock_type == USYNC_PROCESS) {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) _private_mutex_lock(&rwlp->mutex);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) __lwp_rwlock_unlock(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) _private_mutex_unlock(&rwlp->mutex);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw waked = 1;
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw } else {
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw qp = queue_lock(rwlp, MX);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (rd_wr == READ_LOCK)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw atomic_dec_32(rwstate);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw else
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw atomic_and_32(rwstate, ~URW_WRITE_LOCKED);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw waked = rw_queue_release(qp, rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw }
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
0b10de9fc92843e871f48de87f623808c5913a71jpout:
0b10de9fc92843e871f48de87f623808c5913a71jp DTRACE_PROBE2(plockstat, rw__release, rwlp, rd_wr);
0b10de9fc92843e871f48de87f623808c5913a71jp
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw /*
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * Yield to the thread we just waked up, just in case we might
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * be about to grab the rwlock again immediately upon return.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * This is pretty weak but it helps on a uniprocessor and also
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * when cpu affinity has assigned both ourself and the other
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * thread to the same CPU. Note that lwp_yield() will yield
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * the processor only if the writer is at the same or higher
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * priority than ourself. This provides more balanced program
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * behavior; it doesn't guarantee acquisition of the lock by
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw * the pending writer.
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw */
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw if (waked)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw lwp_yield();
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw return (0);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwvoid
c5c4113dfcabb1eed3d4bdf7609de5170027a794nwlrw_unlock(rwlock_t *rwlp)
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw{
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw (void) __rw_unlock(rwlp);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw exit_critical(curthread);
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw}
c5c4113dfcabb1eed3d4bdf7609de5170027a794nw