/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* two requirements not addressed by the system primitives. They
* are that the `enter" operation is optionally interruptible and
* that that they can be re`enter'ed by writers without deadlock.
*
* All of this was borrowed from NFS.
* See: uts/common/fs/nfs/nfs_subr.c
*
* XXX: Could we make this serve our needs instead?
* See: uts/common/os/rwstlock.c
* (and then use it for NFS too)
*/
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
/*
* Only can return non-zero if intr != 0.
*/
int
{
mutex_enter(&l->lock);
/*
* If this is a nested enter, then allow it. There
* must be as many exits as enters through.
*/
/* lock is held for writing by current thread */
l->count--;
/*
* While there is a writer active or writers waiting,
* then wait for them to finish up and move on. Then,
* increment the count to indicate that a reader is
* active.
*/
if (intr) {
lwp->lwp_nostop++;
lwp->lwp_nostop--;
mutex_exit(&l->lock);
return (EINTR);
}
lwp->lwp_nostop--;
} else
}
#ifdef SMBDEBUG
"rwlock @ %p\n", l->count, (void *)&l);
#endif
l->count++;
} else {
/*
* While there are readers active or a writer
* active, then wait for all of the readers
* to finish or for the writer to finish.
* Then, set the owner field to curthread and
* decrement count to indicate that a writer
* is active.
*/
l->waiters++;
if (intr) {
lwp->lwp_nostop++;
lwp->lwp_nostop--;
l->waiters--;
cv_broadcast(&l->cv);
mutex_exit(&l->lock);
return (EINTR);
}
lwp->lwp_nostop--;
} else
l->waiters--;
}
l->count--;
}
mutex_exit(&l->lock);
return (0);
}
/*
* If the lock is available, obtain it and return non-zero. If there is
* already a conflicting lock, return 0 immediately.
*/
int
{
mutex_enter(&l->lock);
/*
* If this is a nested enter, then allow it. There
* must be as many exits as enters through.
*/
/* lock is held for writing by current thread */
l->count--;
/*
* If there is a writer active or writers waiting, deny the
* lock. Otherwise, bump the count of readers.
*/
mutex_exit(&l->lock);
return (0);
}
l->count++;
} else {
/*
* If there are readers active or a writer active, deny the
* lock. Otherwise, set the owner field to curthread and
* decrement count to indicate that a writer is active.
*/
mutex_exit(&l->lock);
return (0);
}
l->count--;
}
mutex_exit(&l->lock);
return (1);
}
void
{
mutex_enter(&l->lock);
/*
* If this is releasing a writer lock, then increment count to
* indicate that there is one less writer active. If this was
* the last of possibly nested writer locks, then clear the owner
* field as well to indicate that there is no writer active
* and wakeup any possible waiting writers or readers.
*
* If releasing a reader lock, then just decrement count to
* indicate that there is one less reader active. If this was
* the last active reader and there are writer(s) waiting,
* then wake up the first.
*/
l->count++;
if (l->count == 0) {
cv_broadcast(&l->cv);
}
} else {
l->count--;
cv_broadcast(&l->cv);
}
mutex_exit(&l->lock);
}
int
{
return (l->count > 0);
return (l->count < 0);
}
/* ARGSUSED */
void
{
l->count = 0;
l->waiters = 0;
}
void
{
mutex_destroy(&l->lock);
cv_destroy(&l->cv);
}