Messages in this thread | | | Date | Wed, 05 Apr 2006 19:15:17 -0600 | From | "Jeff V. Merkey" <> | Subject | Re: readers-writers mutex |
| |
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
/*************************************************************************** * * 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;
}
| |