Adding reader-writer lock primitives.
This commit is contained in:
parent
a6878c822b
commit
9f2567ebbe
@ -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_ */
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user