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.
*/
struct semaphore {
char *sem_name;
char *sem_name;
struct wchan *sem_wchan;
struct spinlock sem_lock;
volatile unsigned sem_count;
volatile unsigned sem_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_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_ */

View File

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