Adding reader-writer lock primitives.

This commit is contained in:
Geoffrey Challen 2016-01-11 21:06:49 -05:00
parent a6878c822b
commit 9f2567ebbe
2 changed files with 110 additions and 75 deletions

View File

@ -44,10 +44,10 @@
* internally. * internally.
*/ */
struct semaphore { struct semaphore {
char *sem_name; char *sem_name;
struct wchan *sem_wchan; struct wchan *sem_wchan;
struct spinlock sem_lock; struct spinlock sem_lock;
volatile unsigned sem_count; volatile unsigned sem_count;
}; };
struct semaphore *sem_create(const char *name, unsigned initial_count); struct semaphore *sem_create(const char *name, unsigned initial_count);
@ -137,5 +137,40 @@ void cv_wait(struct cv *cv, struct lock *lock);
void cv_signal(struct cv *cv, struct lock *lock); void cv_signal(struct cv *cv, struct lock *lock);
void cv_broadcast(struct cv *cv, struct lock *lock); void cv_broadcast(struct cv *cv, struct lock *lock);
/*
* Reader-writer locks.
*
* When the lock is created, no thread should be holding it. Likewise,
* when the lock is destroyed, no thread should be holding it.
*
* The name field is for easier debugging. A copy of the name is
* (should be) made internally.
*/
struct rwlock {
char *rwlock_name;
// add what you need here
// (don't forget to mark things volatile as needed)
};
struct rwlock * rwlock_create(const char *);
void rwlock_destroy(struct rwlock *);
/*
* Operations:
* rwlock_acquire_read - Get the lock for reading. Multiple threads can
* hold the lock for reading at the same time.
* rwlock_release_read - Free the lock.
* rwlock_acquire_write - Get the lock for writing. Only one thread can
* hold the write lock at one time.
* rwlock_release_write - Free the write lock.
*
* These operations must be atomic. You get to write them.
*/
void rwlock_acquire_read(struct rwlock *);
void rwlock_release_read(struct rwlock *);
void rwlock_acquire_write(struct rwlock *);
void rwlock_release_write(struct rwlock *);
#endif /* _SYNCH_H_ */ #endif /* _SYNCH_H_ */

View File

@ -47,18 +47,18 @@
struct semaphore * struct semaphore *
sem_create(const char *name, unsigned initial_count) sem_create(const char *name, unsigned initial_count)
{ {
struct semaphore *sem; struct semaphore *sem;
sem = kmalloc(sizeof(*sem)); sem = kmalloc(sizeof(*sem));
if (sem == NULL) { if (sem == NULL) {
return NULL; return NULL;
} }
sem->sem_name = kstrdup(name); sem->sem_name = kstrdup(name);
if (sem->sem_name == NULL) { if (sem->sem_name == NULL) {
kfree(sem); kfree(sem);
return NULL; return NULL;
} }
sem->sem_wchan = wchan_create(sem->sem_name); sem->sem_wchan = wchan_create(sem->sem_name);
if (sem->sem_wchan == NULL) { if (sem->sem_wchan == NULL) {
@ -68,39 +68,39 @@ sem_create(const char *name, unsigned initial_count)
} }
spinlock_init(&sem->sem_lock); spinlock_init(&sem->sem_lock);
sem->sem_count = initial_count; sem->sem_count = initial_count;
return sem; return sem;
} }
void void
sem_destroy(struct semaphore *sem) sem_destroy(struct semaphore *sem)
{ {
KASSERT(sem != NULL); KASSERT(sem != NULL);
/* wchan_cleanup will assert if anyone's waiting on it */ /* wchan_cleanup will assert if anyone's waiting on it */
spinlock_cleanup(&sem->sem_lock); spinlock_cleanup(&sem->sem_lock);
wchan_destroy(sem->sem_wchan); wchan_destroy(sem->sem_wchan);
kfree(sem->sem_name); kfree(sem->sem_name);
kfree(sem); kfree(sem);
} }
void void
P(struct semaphore *sem) P(struct semaphore *sem)
{ {
KASSERT(sem != NULL); KASSERT(sem != NULL);
/* /*
* May not block in an interrupt handler. * May not block in an interrupt handler.
* *
* For robustness, always check, even if we can actually * For robustness, always check, even if we can actually
* complete the P without blocking. * complete the P without blocking.
*/ */
KASSERT(curthread->t_in_interrupt == false); KASSERT(curthread->t_in_interrupt == false);
/* Use the semaphore spinlock to protect the wchan as well. */ /* Use the semaphore spinlock to protect the wchan as well. */
spinlock_acquire(&sem->sem_lock); spinlock_acquire(&sem->sem_lock);
while (sem->sem_count == 0) { while (sem->sem_count == 0) {
/* /*
* *
* Note that we don't maintain strict FIFO ordering of * Note that we don't maintain strict FIFO ordering of
@ -114,21 +114,21 @@ P(struct semaphore *sem)
* ordering? * ordering?
*/ */
wchan_sleep(sem->sem_wchan, &sem->sem_lock); wchan_sleep(sem->sem_wchan, &sem->sem_lock);
} }
KASSERT(sem->sem_count > 0); KASSERT(sem->sem_count > 0);
sem->sem_count--; sem->sem_count--;
spinlock_release(&sem->sem_lock); spinlock_release(&sem->sem_lock);
} }
void void
V(struct semaphore *sem) V(struct semaphore *sem)
{ {
KASSERT(sem != NULL); KASSERT(sem != NULL);
spinlock_acquire(&sem->sem_lock); spinlock_acquire(&sem->sem_lock);
sem->sem_count++; sem->sem_count++;
KASSERT(sem->sem_count > 0); KASSERT(sem->sem_count > 0);
wchan_wakeone(sem->sem_wchan, &sem->sem_lock); wchan_wakeone(sem->sem_wchan, &sem->sem_lock);
spinlock_release(&sem->sem_lock); spinlock_release(&sem->sem_lock);
@ -141,59 +141,59 @@ V(struct semaphore *sem)
struct lock * struct lock *
lock_create(const char *name) lock_create(const char *name)
{ {
struct lock *lock; struct lock *lock;
lock = kmalloc(sizeof(*lock)); lock = kmalloc(sizeof(*lock));
if (lock == NULL) { if (lock == NULL) {
return NULL; return NULL;
} }
lock->lk_name = kstrdup(name); lock->lk_name = kstrdup(name);
if (lock->lk_name == NULL) { if (lock->lk_name == NULL) {
kfree(lock); kfree(lock);
return NULL; return NULL;
} }
// add stuff here as needed // add stuff here as needed
return lock; return lock;
} }
void void
lock_destroy(struct lock *lock) lock_destroy(struct lock *lock)
{ {
KASSERT(lock != NULL); KASSERT(lock != NULL);
// add stuff here as needed // add stuff here as needed
kfree(lock->lk_name); kfree(lock->lk_name);
kfree(lock); kfree(lock);
} }
void void
lock_acquire(struct lock *lock) lock_acquire(struct lock *lock)
{ {
// Write this // Write this
(void)lock; // suppress warning until code gets written (void)lock; // suppress warning until code gets written
} }
void void
lock_release(struct lock *lock) lock_release(struct lock *lock)
{ {
// Write this // Write this
(void)lock; // suppress warning until code gets written (void)lock; // suppress warning until code gets written
} }
bool bool
lock_do_i_hold(struct lock *lock) lock_do_i_hold(struct lock *lock)
{ {
// Write this // Write this
(void)lock; // suppress warning until code gets written (void)lock; // suppress warning until code gets written
return true; // dummy until code gets written return true; // dummy until code gets written
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -204,47 +204,47 @@ lock_do_i_hold(struct lock *lock)
struct cv * struct cv *
cv_create(const char *name) cv_create(const char *name)
{ {
struct cv *cv; struct cv *cv;
cv = kmalloc(sizeof(*cv)); cv = kmalloc(sizeof(*cv));
if (cv == NULL) { if (cv == NULL) {
return NULL; return NULL;
} }
cv->cv_name = kstrdup(name); cv->cv_name = kstrdup(name);
if (cv->cv_name==NULL) { if (cv->cv_name==NULL) {
kfree(cv); kfree(cv);
return NULL; return NULL;
} }
// add stuff here as needed // add stuff here as needed
return cv; return cv;
} }
void void
cv_destroy(struct cv *cv) cv_destroy(struct cv *cv)
{ {
KASSERT(cv != NULL); KASSERT(cv != NULL);
// add stuff here as needed // add stuff here as needed
kfree(cv->cv_name); kfree(cv->cv_name);
kfree(cv); kfree(cv);
} }
void void
cv_wait(struct cv *cv, struct lock *lock) cv_wait(struct cv *cv, struct lock *lock)
{ {
// Write this // Write this
(void)cv; // suppress warning until code gets written (void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written (void)lock; // suppress warning until code gets written
} }
void void
cv_signal(struct cv *cv, struct lock *lock) cv_signal(struct cv *cv, struct lock *lock)
{ {
// Write this // Write this
(void)cv; // suppress warning until code gets written (void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written (void)lock; // suppress warning until code gets written
} }