123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /*
- * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
- * The President and Fellows of Harvard College.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- /*
- * Synchronization primitives.
- * The specifications of the functions are in synch.h.
- */
- #include <types.h>
- #include <lib.h>
- #include <spinlock.h>
- #include <wchan.h>
- #include <thread.h>
- #include <current.h>
- #include <synch.h>
- ////////////////////////////////////////////////////////////
- //
- // Semaphore.
- struct semaphore *
- sem_create(const char *name, int initial_count)
- {
- struct semaphore *sem;
- KASSERT(initial_count >= 0);
- sem = kmalloc(sizeof(struct semaphore));
- if (sem == NULL) {
- 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) {
- kfree(sem->sem_name);
- kfree(sem);
- return NULL;
- }
- spinlock_init(&sem->sem_lock);
- sem->sem_count = initial_count;
- return sem;
- }
- void
- sem_destroy(struct semaphore *sem)
- {
- 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);
- }
- void
- P(struct semaphore *sem)
- {
- 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);
- spinlock_acquire(&sem->sem_lock);
- while (sem->sem_count == 0) {
- /*
- * Bridge to the wchan lock, so if someone else comes
- * along in V right this instant the wakeup can't go
- * through on the wchan until we've finished going to
- * sleep. Note that wchan_sleep unlocks the wchan.
- *
- * Note that we don't maintain strict FIFO ordering of
- * threads going through the semaphore; that is, we
- * might "get" it on the first try even if other
- * threads are waiting. Apparently according to some
- * textbooks semaphores must for some reason have
- * strict ordering. Too bad. :-)
- *
- * Exercise: how would you implement strict FIFO
- * ordering?
- */
- wchan_lock(sem->sem_wchan);
- spinlock_release(&sem->sem_lock);
- wchan_sleep(sem->sem_wchan);
- spinlock_acquire(&sem->sem_lock);
- }
- KASSERT(sem->sem_count > 0);
- sem->sem_count--;
- spinlock_release(&sem->sem_lock);
- }
- void
- V(struct semaphore *sem)
- {
- KASSERT(sem != NULL);
- spinlock_acquire(&sem->sem_lock);
- sem->sem_count++;
- KASSERT(sem->sem_count > 0);
- wchan_wakeone(sem->sem_wchan);
- spinlock_release(&sem->sem_lock);
- }
- ////////////////////////////////////////////////////////////
- //
- // Lock.
- struct lock * lock_create(const char * name)
- {
- struct lock * lock = kmalloc(sizeof(struct lock));
-
- if (lock == NULL)
- {
- return NULL;
- }
- lock->lk_name = kstrdup(name);
-
- struct wchan * wc = wchan_create(lock->lk_name);
-
- if (lock->lk_name == NULL || wc == NULL)
- {
- kfree(lock->lk_name);
- kfree(lock);
- kfree(wc);
- return NULL;
- }
-
- spinlock_init(&(lock->spin));
- lock->owner = NULL;
- lock->wc = wc;
-
- return lock;
- }
- void lock_destroy(struct lock * lock)
- {
- KASSERT(lock);
-
- spinlock_cleanup(&(lock->spin));
- wchan_destroy(lock->wc);
- kfree(lock->lk_name);
- kfree(lock);
- }
- void lock_acquire(struct lock * lock)
- {
- KASSERT(lock);
- KASSERT(!(lock_do_i_hold(lock)));
- spinlock_acquire(&(lock->spin));
-
- while (lock->owner)
- {
- wchan_lock(lock->wc);
- spinlock_release(&(lock->spin));
- wchan_sleep(lock->wc);
- spinlock_acquire(&(lock->spin));
- }
-
- lock->owner = curthread;
- spinlock_release(&(lock->spin));
- }
- void lock_release(struct lock * lock)
- {
- KASSERT(lock);
- KASSERT(lock_do_i_hold(lock));
-
- spinlock_acquire(&(lock->spin));
- lock->owner = NULL;
- wchan_wakeone(lock->wc);
- spinlock_release(&(lock->spin));
- }
- bool lock_do_i_hold(struct lock * lock)
- {
- KASSERT(lock);
-
- return (lock->owner == curthread);
- }
- ////////////////////////////////////////////////////////////
- //
- // CV
- struct cv * cv_create(const char * name)
- {
- struct cv * cv = kmalloc(sizeof(struct cv));
-
- if (cv == NULL)
- {
- return NULL;
- }
-
- cv->cv_name = kstrdup(name);
- struct wchan * wc = wchan_create(cv->cv_name);
-
- if (cv->cv_name == NULL || wc == NULL)
- {
- kfree(cv->cv_name);
- kfree(cv);
- kfree(wc);
- return NULL;
- }
- cv->wc = wc;
- return cv;
- }
- void cv_destroy(struct cv * cv)
- {
- KASSERT(cv);
-
- wchan_destroy(cv->wc);
- kfree(cv->cv_name);
- kfree(cv);
- }
- void cv_wait(struct cv * cv, struct lock * lock)
- {
- KASSERT(lock_do_i_hold(lock));
-
- wchan_lock(cv->wc);
- lock_release(lock);
- wchan_sleep(cv->wc);
- lock_acquire(lock);
- }
- void
- cv_signal(struct cv * cv, struct lock * lock)
- {
- KASSERT(lock_do_i_hold(lock));
- KASSERT(cv);
-
- wchan_wakeone(cv->wc);
- }
- void
- cv_broadcast(struct cv * cv, struct lock * lock)
- {
- KASSERT(lock_do_i_hold(lock));
- KASSERT(cv);
-
- wchan_wakeall(cv->wc);
- }
|