* readers-writers mutex
@ 2006-04-05 22:21 Joshua Hudson
2006-04-06 1:06 ` Arjan van de Ven
2006-04-06 1:15 ` Jeff V. Merkey
0 siblings, 2 replies; 4+ messages in thread
From: Joshua Hudson @ 2006-04-05 22:21 UTC (permalink / raw)
To: linux-kernel
Since we are moving from semaphores to mutex, there should be a
mutex_rw. I had a try
at creating one (might as well convert from sem_rw). I'll bet somebody
here can do a
lot better, but this will do if need be.
--- linux-2.6.16.1-stock/include/linux/mutex_rw.h 1969-12-31
16:00:00.000000000 -0800
+++ linux-2.6.16.1-nvl/include/linux/mutex_rw.h 2006-04-04
18:11:56.000000000 -0700
@@ -0,0 +1,60 @@
+/* Linux RW mutex
+ * This file: GNU GPL v2 or later, Joshua Hudson <joshudson@gmail.com>
+ *
+ * Somebody else can make this fast. I just made this work.
+ *
+ * DANGER! Change of this file will break module binaries if any
+ * rw mutex is shared between main kernel and modules or between
+ * modules with a different version.
+ */
+
+#ifndef __KERNEL_MUTEX_RW
+#define __KERNEL_MUTEX_RW
+#ifdef __KERNEL__
+
+#include <linux/mutex.h>
+
+struct rw_mutex {
+ struct mutex r_mutex;
+ struct mutex w_mutex;
+ unsigned n_readers;
+};
+
+static inline void rw_mutex_init(struct rw_mutex *rw)
+{
+ mutex_init(&rw->r_mutex);
+ mutex_init(&rw->w_mutex);
+ rw->n_readers = 0;
+}
+
+static inline void rw_mutex_destroy(struct rw_mutex *rw)
+{
+ mutex_destroy(&rw->r_mutex);
+ mutex_destroy(&rw->w_mutex);
+}
+
+static inline void mutex_lock_w(struct rw_mutex *rw)
+{
+ mutex_lock(&rw->w_mutex);
+}
+
+static inline void mutex_unlock_w(struct rw_mutex *rw)
+{
+ mutex_unlock(&rw->w_mutex);
+}
+
+static inline void mutex_lock_r(struct rw_mutex *rw)
+{
+ mutex_lock(&rw->r_mutex);
+ if (++rw->n_readers == 1)
+ mutex_lock(&rw->w_mutex);
+ mutex_unlock(&rw->r_mutex);
+}
+
+static inline void mutex_unlock_r(struct rw_mutex *rw)
+{
+ mutex_lock(&rw->r_mutex);
+ if (--rw->n_readers == 0)
+ mutex_unlock(&rw->w_mutex);
+ mutex_unlock(&rw->r_mutex);
+}
+
+#endif
+#endif
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: readers-writers mutex
2006-04-05 22:21 readers-writers mutex Joshua Hudson
@ 2006-04-06 1:06 ` Arjan van de Ven
2006-04-06 1:59 ` Joshua Hudson
2006-04-06 1:15 ` Jeff V. Merkey
1 sibling, 1 reply; 4+ messages in thread
From: Arjan van de Ven @ 2006-04-06 1:06 UTC (permalink / raw)
To: Joshua Hudson; +Cc: linux-kernel
On Wed, 2006-04-05 at 15:21 -0700, Joshua Hudson wrote:
> Since we are moving from semaphores to mutex, there should be a
> mutex_rw.
should there really? We discussed this briefly during the mutex work
the conclusion was that rw_sems
1) are rare (thankfully; they're highly expensive)
2) do not have mutex semantics
so... can you explain how your rw_mutex is behaving different from an
rw_sem, and can you explain what the gains are for that conversion?
(eg for mutex it was better defined semantics, lots better debugging
(possible due to the semantics) and more performance). What is that for
rw_mutex ?
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: readers-writers mutex
2006-04-05 22:21 readers-writers mutex Joshua Hudson
2006-04-06 1:06 ` Arjan van de Ven
@ 2006-04-06 1:15 ` Jeff V. Merkey
1 sibling, 0 replies; 4+ messages in thread
From: Jeff V. Merkey @ 2006-04-06 1:15 UTC (permalink / raw)
To: Joshua Hudson; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2468 bytes --]
Joshua Hudson wrote:
>Since we are moving from semaphores to mutex, there should be a
>mutex_rw. I had a try
>at creating one (might as well convert from sem_rw). I'll bet somebody
>here can do a
>lot better, but this will do if need be.
>
>--- linux-2.6.16.1-stock/include/linux/mutex_rw.h 1969-12-31
>16:00:00.000000000 -0800
>+++ linux-2.6.16.1-nvl/include/linux/mutex_rw.h 2006-04-04
>18:11:56.000000000 -0700
>@@ -0,0 +1,60 @@
>+/* Linux RW mutex
>+ * This file: GNU GPL v2 or later, Joshua Hudson <joshudson@gmail.com>
>+ *
>+ * Somebody else can make this fast. I just made this work.
>+ *
>+ * DANGER! Change of this file will break module binaries if any
>+ * rw mutex is shared between main kernel and modules or between
>+ * modules with a different version.
>+ */
>+
>+#ifndef __KERNEL_MUTEX_RW
>+#define __KERNEL_MUTEX_RW
>+#ifdef __KERNEL__
>+
>+#include <linux/mutex.h>
>+
>+struct rw_mutex {
>+ struct mutex r_mutex;
>+ struct mutex w_mutex;
>+ unsigned n_readers;
>+};
>+
>+static inline void rw_mutex_init(struct rw_mutex *rw)
>+{
>+ mutex_init(&rw->r_mutex);
>+ mutex_init(&rw->w_mutex);
>+ rw->n_readers = 0;
>+}
>+
>+static inline void rw_mutex_destroy(struct rw_mutex *rw)
>+{
>+ mutex_destroy(&rw->r_mutex);
>+ mutex_destroy(&rw->w_mutex);
>+}
>+
>+static inline void mutex_lock_w(struct rw_mutex *rw)
>+{
>+ mutex_lock(&rw->w_mutex);
>+}
>+
>+static inline void mutex_unlock_w(struct rw_mutex *rw)
>+{
>+ mutex_unlock(&rw->w_mutex);
>+}
>+
>+static inline void mutex_lock_r(struct rw_mutex *rw)
>+{
>+ mutex_lock(&rw->r_mutex);
>+ if (++rw->n_readers == 1)
>+ mutex_lock(&rw->w_mutex);
>+ mutex_unlock(&rw->r_mutex);
>+}
>+
>+static inline void mutex_unlock_r(struct rw_mutex *rw)
>+{
>+ mutex_lock(&rw->r_mutex);
>+ if (--rw->n_readers == 0)
>+ mutex_unlock(&rw->w_mutex);
>+ mutex_unlock(&rw->r_mutex);
>+}
>+
>+#endif
>+#endif
>-
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at http://www.tux.org/lkml/
>
>
>
Race conditions here.
Try this code. These have been tested and I have been using the code for
couple of years in another OS (which is just about done now and is in
alpha and beta and little more SMP friendly).
Jeff
[-- Attachment #2: rwlock.c --]
[-- Type: text/x-csrc, Size: 22909 bytes --]
/***************************************************************************
*
* Copyright (c) 2005, 2006 Cherokee Nation. All Rights Reserved.
*
* This Program is released under GPLv3
*
* AUTHOR : Jeff V. Merkey
* FILE : RWLOCK.C
* DESCRIP : Multi-Processing Reader/Writer Locks Gadugi v7
* DATE : October 23, 2004
*
***************************************************************************/
#include "stdarg.h"
#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "string.h"
#include "kernel.h"
#include "keyboard.h"
#include "screen.h"
#include "types.h"
#include "emit.h"
#include "dos.h"
#include "tss.h"
#include "os.h"
#include "mps.h"
#include "hal.h"
#include "timer.h"
#include "peexe.h"
#include "malloc.h"
#include "free.h"
#include "event.h"
#define WRITER_OWNED -10
#define READER_OWNED -11
#define UNOWNED -12
rwlock_t *rwlock_init(rwlock_t *rwlock);
rwlock_t *rwlock_alloc(void);
LONG rwlock_free(rwlock_t *rwlock);
LONG rwlock_read_lock(rwlock_t *rwlock);
LONG rwlock_write_lock(rwlock_t *rwlock);
LONG rwlock_read_try_lock(rwlock_t *rwlock);
LONG rwlock_write_try_lock(rwlock_t *rwlock);
LONG rwlock_unlock(rwlock_t *rwlock);
LONG rwlock_reader_to_writer(rwlock_t *rwlock);
LONG rwlock_reader_to_writer_unordered(rwlock_t *rwlock);
LONG rwlock_writer_to_reader(rwlock_t *rwlock);
LONG rwlock_release(rwlock_t *rwlock);
PROCESS *get_rwlock_process(rwlock_t *rwlock);
void put_rwlock_process(rwlock_t *rwlock, PROCESS *p);
rwlock_t *rwlock_init(rwlock_t *rwlock)
{
if (rwlock && !rwlock->signature)
{
SetData((LONG *) rwlock, 0, sizeof(rwlock_t));
rwlock->signature = LRWLOCK_SIGNATURE;
rwlock->flags = UNOWNED;
return (rwlock_t *) rwlock;
}
return 0;
}
rwlock_t *rwlock_alloc(void)
{
register rwlock_t *rwlock;
rwlock = kmalloc(sizeof(rwlock_t));
if (rwlock)
{
SetData((LONG *) rwlock, 0, sizeof(rwlock_t));
rwlock->signature = RWLOCK_SIGNATURE;
rwlock->flags = UNOWNED;
return (rwlock_t *) rwlock;
}
return 0;
}
LONG rwlock_free(rwlock_t *rwlock)
{
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
if (!rwlock_release(rwlock))
{
if (rwlock->signature == RWLOCK_SIGNATURE)
kfree(rwlock);
else
rwlock->signature = 0;
return 0;
}
return -2;
}
return -1;
}
#if RWLOCK_TRACE
BYTE *get_RW_TYPE(LONG p)
{
switch (p)
{
case RREAD_LOCK:
return "READ_LOCK";
case RREAD_UNLOCK:
return "READ_UNLOCK";
case WWRITE_LOCK:
return "WRITE_LOCK";
case WWRITE_UNLOCK:
return "WRITE_UNLOCK";
default:
return "????";
}
}
BYTE *get_RW_OP(LONG p)
{
switch (p)
{
case READER_LOCK:
return "READER_LOCK ";
case READER_UNLOCK:
return "READER_UNLOCK";
case READER_SLEEP:
return "READER_SLEEP ";
case READER_WAKE:
return "READER_WAKE ";
case WRITER_LOCK:
return "WRITER_LOCK ";
case WRITER_UNLOCK:
return "WRITER_UNLOCK";
case WRITER_SLEEP:
return "WRITER_SLEEP ";
case WRITER_WAKE:
return "WRITER_WAKE ";
default:
return "???? ";
}
}
void RW_DISPLAY(SCREEN *screen, rwlock_t *rwlock)
{
register LONG i;
SetPauseMode(screen, screen->nLines - 5);
printfScreen(screen, "RWIndex %d\n");
for (i=0; i < 256; i++)
{
printfScreen(screen, "process-%08X time-%08X target-%08X s-%s t-%s\n",
rwlock->RWProcess[i],
rwlock->RWTime[i],
rwlock->RWTarget[i],
get_RW_OP(rwlock->RWOp[i]),
get_RW_TYPE(rwlock->RWType[i]));
}
ClearPauseMode(screen);
return;
}
void RW_TRACE(rwlock_t *rwlock, LONG event, LONG target, LONG type)
{
LONG base, counter;
GetSystemDTSC(&base, &counter);
rwlock->RWProcess[rwlock->RWIndex & 0xFF] = (LONG) get_running_process();
rwlock->RWOp[rwlock->RWIndex & 0xFF] = event;
rwlock->RWTarget[rwlock->RWIndex & 0xFF] = target;
rwlock->RWType[rwlock->RWIndex & 0xFF] = type;
rwlock->RWTime[rwlock->RWIndex & 0xFF] = (LONG) base;
rwlock->RWIndex++;
}
#endif
LONG rwlock_read_lock(rwlock_t *rwlock)
{
register PROCESS *p = get_running_process();
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
p->syncFlag = 0;
switch (rwlock->flags)
{
case WRITER_OWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_SLEEP, (LONG) p, RREAD_LOCK);
#endif
spin_lock(&p->threadMutex); // lock current thread
put_rwlock_process(rwlock, p);
p->stackPointer = 0;
p->threadState = PS_SLEEP;
p->syncObject = rwlock;
p->syncState = PROCESS_READER_BLOCKED_SYNC;
spin_unlock(&rwlock->mutex);
thread_switch(); // context switch will unlock thread
cli();
set_flags(flags);
return p->syncFlag;
case READER_OWNED:
if (rwlock->writers)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_SLEEP, (LONG) p, RREAD_LOCK);
#endif
spin_lock(&p->threadMutex); // lock current thread
put_rwlock_process(rwlock, p);
p->stackPointer = 0;
p->threadState = PS_SLEEP;
p->syncObject = rwlock;
p->syncState = PROCESS_READER_BLOCKED_SYNC;
spin_unlock(&rwlock->mutex);
thread_switch(); // context switch will unlock thread
cli();
set_flags(flags);
return p->syncFlag;
}
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_LOCK, 0, RREAD_LOCK);
#endif
rwlock->flags = (LONG) READER_OWNED;
rwlock->readers++; // set reader count
spin_unlock(&rwlock->mutex);
set_flags(flags);
return p->syncFlag;
case UNOWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_LOCK, 0, RREAD_LOCK);
#endif
rwlock->flags = (LONG) READER_OWNED;
rwlock->readers++; // set reader count
spin_unlock(&rwlock->mutex);
set_flags(flags);
return p->syncFlag;
default:
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_write_lock(rwlock_t *rwlock)
{
register PROCESS *p = get_running_process();
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
p->syncFlag = 0;
switch (rwlock->flags)
{
case READER_OWNED:
case WRITER_OWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_SLEEP, (LONG) p, WWRITE_LOCK);
#endif
spin_lock(&p->threadMutex); // lock current thread
put_rwlock_process(rwlock, p);
rwlock->writers++;
p->stackPointer = 0;
p->threadState = PS_SLEEP;
p->syncObject = rwlock;
p->syncState = PROCESS_WRITER_BLOCKED_SYNC;
spin_unlock(&rwlock->mutex);
thread_switch(); // context switch will unlock thread
cli();
set_flags(flags);
return p->syncFlag;
case UNOWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_LOCK);
#endif
rwlock->flags = (LONG) WRITER_OWNED;
rwlock->owner = (LONG) p;
spin_unlock(&rwlock->mutex);
set_flags(flags);
return p->syncFlag;
default:
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_read_try_lock(rwlock_t *rwlock)
{
register PROCESS *p = get_running_process();
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
p->syncFlag = 0;
switch (rwlock->flags)
{
case WRITER_OWNED:
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 1;
case READER_OWNED:
if (rwlock->writers)
{
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 1;
}
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_LOCK, 0, RREAD_TRY_LOCK);
#endif
rwlock->flags = (LONG) READER_OWNED;
rwlock->readers++; // set reader count
spin_unlock(&rwlock->mutex);
set_flags(flags);
return p->syncFlag;
case UNOWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_LOCK, 0, RREAD_TRY_LOCK);
#endif
rwlock->flags = (LONG) READER_OWNED;
rwlock->readers++; // set reader count
spin_unlock(&rwlock->mutex);
set_flags(flags);
return p->syncFlag;
default:
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_write_try_lock(rwlock_t *rwlock)
{
register PROCESS *p = get_running_process();
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
p->syncFlag = 0;
switch (rwlock->flags)
{
case READER_OWNED:
case WRITER_OWNED:
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 1;
case UNOWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_TRY_LOCK);
#endif
rwlock->flags = (LONG) WRITER_OWNED;
rwlock->owner = (LONG) p;
spin_unlock(&rwlock->mutex);
set_flags(flags);
return p->syncFlag;
default:
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_read_unlock(rwlock_t *rwlock)
{
register PROCESS *p;
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
switch (rwlock->flags)
{
case WRITER_OWNED:
panic("rwlock_read_unlock called with writer owning rwlock");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
case READER_OWNED:
if (rwlock->readers)
rwlock->readers--;
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_UNLOCK, 0, RREAD_UNLOCK);
#endif
if (!rwlock->readers)
{
rwlock->flags = UNOWNED;
if (rwlock->head)
{
p = rwlock->head;
if (p->syncState != PROCESS_WRITER_BLOCKED_SYNC)
{
panic("rwlock_read_unlock called with sleeping READER");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
p = get_rwlock_process(rwlock);
rwlock->writers--;
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, RREAD_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, RREAD_UNLOCK);
#endif
rwlock->flags = WRITER_OWNED;
rwlock->owner = (LONG) p;
}
spin_unlock(&p->threadMutex); // unlock thread
}
}
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
case UNOWNED:
default:
panic("rwlock_read_unlock called in inconsistent state");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_write_unlock(rwlock_t *rwlock)
{
register PROCESS *p, *curr;
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
curr = get_running_process();
if (rwlock->owner != (LONG) curr)
{
panic("rwlock_write_unlock called by process other than owner");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
switch (rwlock->flags)
{
case WRITER_OWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_UNLOCK, 0, WWRITE_UNLOCK);
#endif
rwlock->owner = 0;
rwlock->flags = UNOWNED;
if (rwlock->head)
{
p = rwlock->head;
if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
{
p = get_rwlock_process(rwlock);
rwlock->writers--;
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_UNLOCK);
#endif
rwlock->flags = WRITER_OWNED;
rwlock->owner = (LONG) p;
}
spin_unlock(&p->threadMutex); // unlock thread
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
}
while (rwlock->head)
{
p = rwlock->head;
if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
break;
p = get_rwlock_process(rwlock);
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_LOCK, 0, WWRITE_UNLOCK);
#endif
rwlock->flags = READER_OWNED;
rwlock->readers++;
rwlock->owner = 0; }
}
spin_unlock(&p->threadMutex); // unlock thread
}
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
case READER_OWNED:
panic("rwlock_write_unlock called with reader owning rwlock");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
case UNOWNED:
default:
panic("rwlock_write_unlock called in inconsistent state");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_reader_to_writer(rwlock_t *rwlock)
{
register PROCESS *p;
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
switch (rwlock->flags)
{
case WRITER_OWNED:
panic("rwlock_reader_to_writer called with writer owning rwlock");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
case READER_OWNED:
if (rwlock->readers)
rwlock->readers--;
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_UNLOCK, 0, RREAD_UNLOCK);
#endif
if (!rwlock->readers)
{
rwlock->flags = UNOWNED;
if (rwlock->head)
{
p = rwlock->head;
if (p->syncState != PROCESS_WRITER_BLOCKED_SYNC)
{
panic("rwlock_read_unlock called with sleeping READER");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
p = get_rwlock_process(rwlock);
rwlock->writers--;
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, RREAD_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, RREAD_UNLOCK);
#endif
rwlock->flags = WRITER_OWNED;
rwlock->owner = (LONG) p;
}
spin_unlock(&p->threadMutex); // unlock thread
}
}
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
case UNOWNED:
default:
panic("rwlock_reader_to_writer called in inconsistent state");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_reader_to_writer_unordered(rwlock_t *rwlock)
{
register PROCESS *p;
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
switch (rwlock->flags)
{
case WRITER_OWNED:
panic("rwlock_reader_to_writer_unordered called with writer owning rwlock");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
case READER_OWNED:
if (rwlock->readers)
rwlock->readers--;
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_UNLOCK, 0, RREAD_UNLOCK);
#endif
if (!rwlock->readers)
{
rwlock->flags = UNOWNED;
if (rwlock->head)
{
p = rwlock->head;
if (p->syncState != PROCESS_WRITER_BLOCKED_SYNC)
{
panic("rwlock_read_unlock called with sleeping READER");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
p = get_rwlock_process(rwlock);
rwlock->writers--;
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, RREAD_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, RREAD_UNLOCK);
#endif
rwlock->flags = WRITER_OWNED;
rwlock->owner = (LONG) p;
}
spin_unlock(&p->threadMutex); // unlock thread
}
}
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
case UNOWNED:
default:
panic("rwlock_reader_to_writer_unordered called in inconsistent state");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
LONG rwlock_writer_to_reader(rwlock_t *rwlock)
{
register PROCESS *p, *curr;
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
curr = get_running_process();
if (rwlock->owner != (LONG) curr)
{
panic("rwlock_writer_to_reader called by process other than owner");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
switch (rwlock->flags)
{
case WRITER_OWNED:
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_UNLOCK, 0, WWRITE_UNLOCK);
#endif
rwlock->owner = 0;
rwlock->flags = UNOWNED;
if (rwlock->head)
{
p = rwlock->head;
if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
{
p = get_rwlock_process(rwlock);
rwlock->writers--;
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_UNLOCK);
#endif
rwlock->flags = WRITER_OWNED;
rwlock->owner = (LONG) p;
}
spin_unlock(&p->threadMutex); // unlock thread
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
}
while (rwlock->head)
{
p = rwlock->head;
if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
break;
p = get_rwlock_process(rwlock);
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = 0;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
RW_TRACE(rwlock, READER_LOCK, 0, WWRITE_UNLOCK);
#endif
rwlock->flags = READER_OWNED;
rwlock->readers++;
rwlock->owner = 0; }
}
spin_unlock(&p->threadMutex); // unlock thread
}
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
case READER_OWNED:
panic("rwlock_writer_to_reader called with reader owning rwlock");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
case UNOWNED:
default:
panic("rwlock_writer_to_reader called in inconsistent state");
spin_unlock(&rwlock->mutex);
set_flags(flags);
return -1;
}
}
return -1;
}
PROCESS *get_rwlock_process(rwlock_t *rwlock)
{
register PROCESS *p, *list;
if (rwlock->head)
{
p = rwlock->head;
list = (PROCESS *) rwlock->head = (void *) p->syncNext;
if (list)
list->syncPrior = NULL;
else
rwlock->tail = NULL;
return p;
}
return 0;
}
void put_rwlock_process(rwlock_t *rwlock, PROCESS *p)
{
register PROCESS *search, *list;
search = rwlock->head;
while (search)
{
if (search == p)
return;
search = search->syncNext;
}
if (!rwlock->head)
{
rwlock->head = rwlock->tail = p;
p->syncNext = p->syncPrior = 0;
}
else
{
list = (PROCESS *) rwlock->tail;
list->syncNext = p;
p->syncNext = 0;
p->syncPrior = rwlock->tail;
rwlock->tail = p;
}
return;
}
LONG rwlock_release(rwlock_t *rwlock)
{
register PROCESS *p, *list;
register LONG flags;
if (rwlock->signature == RWLOCK_SIGNATURE ||
rwlock->signature == LRWLOCK_SIGNATURE)
{
flags = get_flags();
spin_lock(&rwlock->mutex);
p = rwlock->head;
while (p)
{
list = p->syncNext;
spin_lock(&p->threadMutex); // lock thread
if (p->threadState == PS_SLEEP)
{
p->threadState = PS_ACTIVE;
p->syncObject = 0;
p->syncState = 0;
p->syncFlag = -2;
if (rwlock->waiters)
rwlock->waiters--;
(!p->processorBinding)
? put_dispatch(p)
: put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
}
spin_unlock(&p->threadMutex); // unlock thread
p = list;
}
rwlock->owner = 0;
spin_unlock(&rwlock->mutex);
set_flags(flags);
return 0;
}
return -1;
}
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: readers-writers mutex
2006-04-06 1:06 ` Arjan van de Ven
@ 2006-04-06 1:59 ` Joshua Hudson
0 siblings, 0 replies; 4+ messages in thread
From: Joshua Hudson @ 2006-04-06 1:59 UTC (permalink / raw)
To: linux-kernel
On 4/5/06, Arjan van de Ven <arjan@infradead.org> wrote:
> On Wed, 2006-04-05 at 15:21 -0700, Joshua Hudson wrote:
> > Since we are moving from semaphores to mutex, there should be a
> > mutex_rw.
>
> should there really? We discussed this briefly during the mutex work
> the conclusion was that rw_sems
> 1) are rare (thankfully; they're highly expensive)
> 2) do not have mutex semantics
>
> so... can you explain how your rw_mutex is behaving different from an
> rw_sem, and can you explain what the gains are for that conversion?
> (eg for mutex it was better defined semantics, lots better debugging
> (possible due to the semantics) and more performance). What is that for
> rw_mutex ?
>
Just this: it inherits the better debugging from mutex. And if a
rw_sem is more expensive than two mutexes, this is cheaper where
it can be used (no ability to downconvert a lock).
Oh, and if nobody uses it, kernel size changes by 0k.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2006-04-06 1:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-05 22:21 readers-writers mutex Joshua Hudson
2006-04-06 1:06 ` Arjan van de Ven
2006-04-06 1:59 ` Joshua Hudson
2006-04-06 1:15 ` Jeff V. Merkey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox