From: willy@ldl.fc.hp.com (Matthew Wilcox)
To: parisc-linux@lists.parisc-linux.org
Subject: [parisc-linux] rwsems
Date: Wed, 7 Feb 2001 19:44:30 -0700 [thread overview]
Message-ID: <20010207194430.C620@zumpano.fc.hp.com> (raw)
Currently, our read/write semaphores are NOPs. This is not so good :-)
Here's a scheme i've devised for doing rwsems moderately efficiently;
if anyone can think of a better scheme, please shout.
(removed debugging code for clarity)
semaphore.h:
#define RWSEM_WRITER -1
#define RWSEM_MASK 0xC0000000
#define RWSEM_BIAS_WRITE 0xC0000000
#define RWSEM_BIAS_READ 0x80000000
struct rw_semaphore {
spinlock_t sentry;
signed int rw_count;
wait_queue_head_t readers;
wait_queue_head_t writers;
};
extern inline void down_read(struct rw_semaphore *sem)
{
spin_lock(&sem->sentry);
if (sem->rw_count < 0)
__down_read_failed(sem);
sem->rw_count++;
spin_unlock(&sem->sentry);
}
extern inline void down_write(struct rw_semaphore *sem)
{
spin_lock(&sem->sentry);
if (sem->rw_count != 0)
__down_write_failed(sem);
sem->rw_count += RWSEM_WRITER;
spin_unlock(&sem->sentry);
}
extern inline void up_read(struct rw_semaphore *sem)
{
spin_lock(&sem->sentry);
if (sem->rw_count-- < 0)
__up_read_wakeup(sem);
spin_unlock(&sem->sentry);
}
extern inline void up_write(struct rw_semaphore *sem)
{
spin_lock(&sem->sentry);
sem->rw_count -= RWSEM_WRITER;
if (sem->rw_count != 0)
__up_write_wakeup(sem);
spin_unlock(&sem->sentry);
}
semaphore.c:
/* We must wait for a writer to up the semaphore */
void down_read_failed(struct rw_semaphore *sem)
{
DECLARE_WAITQUEUE(wait, current);
/* If we're the first waiter, indicate that we exist */
if ((sem->rw_count & RWSEM_MASK) == 0)
sem->rw_count |= RWSEM_READ;
__add_wait_queue(&sem->readers, &wait);
spin_unlock(&sem->sentry);
while (sem->rw_count < 0) {
set_task_state(current, TASK_UNINTERRUPTIBLE);
if (sem->rw_count >= 0)
break; /* We get the lock */
schedule();
}
spin_lock(&sem->sentry);
__remove_wait_queue(&sem->readers, &wait);
current->state = TASK_RUNNING;
}
/* Wait for all previous readers to up the sempahore.
* Since we're a writer, we'll make ourselves exclusive.
*/
void down_write_failed(struct rw_semaphore *sem)
{
DECLARE_WAITQUEUE(wait, current);
/* If we're the first waiter, indicate that we exist */
if ((sem->rw_count & RWSEM_MASK) == 0)
sem->rw_count |= RWSEM_WRITE;
wait.flags = WQ_FLAG_EXCLUSIVE;
__add_wait_queue_tail(&sem->writers, &wait);
spin_unlock(&sem->sentry);
while (sem->rw_count != 0) {
set_task_state(current, TASK_UNINTERRUPTIBLE);
if (sem->rw_count == 0)
break; /* We get the lock */
schedule();
}
spin_lock(&sem->sentry);
__remove_wait_queue(&sem->writers, &wait);
current->state = TASK_RUNNING;
}
/* up_read_wakeup gets called spuriously when a writer is waiting
* for the lock. That's OK, this is slowpath now anyway.
*/
void up_read_wakeup(struct rw_semaphore *sem)
{
/* Check to see if other readers need to up the semaphore */
if ((sem->rw_count &~ RWSEM_MASK) != 0)
return;
up_write_wakeup(sem);
}
void up_write_wakeup(struct rw_semaphore *sem)
{
/* Figure out what state to go to next. */
if ((sem->rw_count & RWSEM_MASK) == RWSEM_WRITE) {
int more_writers = (sem->writers.task_list.next != sem->writers.task_list.prev);
int more_readers = list_empty(&sem->readers.task_list);
if (more_writers) {
if (more_readers) {
sem->rw_count = RWSEM_READ;
} else {
sem->rw_count = RWSEM_WRITE;
}
} else {
if (!more_readers) {
sem->rw_count = 0;
} else {
sem->rw_count = RWSEM_READ;
}
}
wake_up(&sem->writers);
} else {
int more_writers = list_empty(&sem->writers.task_list);
if (more_writers) {
sem->rw_count = RWSEM_WRITE;
} else {
sem->rw_count = 0;
}
wake_up(&sem->readers);
}
}
I suspect I could encode more information in the rwcount that might
make it unnecessary to check the waitqueues explicitly.
reply other threads:[~2001-02-08 2:48 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20010207194430.C620@zumpano.fc.hp.com \
--to=willy@ldl.fc.hp.com \
--cc=parisc-linux@lists.parisc-linux.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox