From: Peter Dinda Date: Mon, 30 Jun 2014 19:22:07 +0000 (-0500) Subject: Add shared-exclusive (readers-writer) locks X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=626494b00fd477070f7eb43693eb16c4dc45f66b Add shared-exclusive (readers-writer) locks --- diff --git a/palacios/include/palacios/vmm_lock.h b/palacios/include/palacios/vmm_lock.h index 575bb81..5531aea 100644 --- a/palacios/include/palacios/vmm_lock.h +++ b/palacios/include/palacios/vmm_lock.h @@ -23,20 +23,50 @@ #ifdef __V3VEE__ #include +// Exclusive locks + typedef addr_t v3_lock_t; int v3_lock_init(v3_lock_t * lock); void v3_lock_deinit(v3_lock_t * lock); +// Interreupts unaffected void v3_lock(v3_lock_t lock); void v3_unlock(v3_lock_t lock); - +// Interrupts disabled addr_t v3_lock_irqsave(v3_lock_t lock); void v3_unlock_irqrestore(v3_lock_t lock, addr_t irq_state); +// Reader-writer locks + +typedef struct v3_rw_lock { + v3_lock_t lock; + sint64_t reader_count; +} v3_rw_lock_t; + +int v3_rw_lock_init(v3_rw_lock_t *lock); +void v3_rw_lock_deinit(v3_rw_lock_t *lock); + +// A read lock is not exclusive and does not +// affect interrupts +void v3_read_lock(v3_rw_lock_t *lock); +void v3_read_unlock(v3_rw_lock_t *lock); + +// A write lock is exclusive and may affect +// interrupts + +// leaves interrupt state alone +void v3_write_lock(v3_rw_lock_t *lock); +void v3_read_unlock(v3_rw_lock_t *lock); + +// turn interrupts off +addr_t v3_write_lock_irqsave(v3_rw_lock_t *lock); +void v3_write_unlock_irqrestore(v3_rw_lock_t *lock, addr_t irq_state); + + #endif #endif diff --git a/palacios/src/palacios/vmm_lock.c b/palacios/src/palacios/vmm_lock.c index 23569d2..7b3a091 100644 --- a/palacios/src/palacios/vmm_lock.c +++ b/palacios/src/palacios/vmm_lock.c @@ -57,3 +57,79 @@ addr_t v3_lock_irqsave(v3_lock_t lock) { void v3_unlock_irqrestore(v3_lock_t lock, addr_t irq_state) { os_hooks->mutex_unlock_irqrestore((void *)lock,(void*)irq_state); } + + +int v3_rw_lock_init(v3_rw_lock_t *lock) +{ + lock->reader_count=0; + return v3_lock_init(&(lock->lock)); +} + +void v3_rw_lock_deinit(v3_rw_lock_t *lock) +{ + v3_lock_deinit(&(lock->lock)); + lock->reader_count=0; +} + +void v3_read_lock(v3_rw_lock_t *lock) +{ + addr_t flags; + + flags=v3_lock_irqsave(lock->lock); + lock->reader_count++; + v3_unlock_irqrestore(lock->lock,flags); + // readers can come in after us, writers cannot +} +void v3_read_unlock(v3_rw_lock_t *lock) +{ + addr_t flags; + + flags=v3_lock_irqsave(lock->lock); + lock->reader_count--; + v3_unlock_irqrestore(lock->lock,flags); + // readers can come in after us, and also writers if reader_count==0 +} + +void v3_write_lock(v3_rw_lock_t *lock) +{ + // a less hideous implementation is possible, of course... + while (1) { + v3_lock(lock->lock); + if (!(lock->reader_count)) { + break; + } + v3_unlock(lock->lock); + V3_Yield(); + } + // holding lock now - reader or writer cannot come in after us +} + +addr_t v3_write_lock_irqsave(v3_rw_lock_t *lock) +{ + addr_t flags; + + while (1) { + flags=v3_lock_irqsave(lock->lock); + if (!(lock->reader_count)) { + break; + } + v3_unlock_irqrestore(lock->lock,flags); + V3_Yield(); + } + // holding lock now with interrupts off - reader or writer canot come in after us + return flags; +} + +void v3_write_unlock(v3_rw_lock_t *lock) +{ + // I am already holding this lock + v3_unlock(lock->lock); + // readers/writers can now come in +} + +void v3_write_unlock_irqrestore(v3_rw_lock_t *lock, addr_t irq_state) +{ + // I am already holding this lock with interrupts off + v3_unlock_irqrestore(lock->lock,irq_state); + // readers/writers can now come in +}