/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* Synchronization primitives.31* The specifications of the functions are in synch.h.32*/3334#include <types.h>35#include <lib.h>36#include <spinlock.h>37#include <wchan.h>38#include <thread.h>39#include <current.h>40#include <synch.h>4142////////////////////////////////////////////////////////////43//44// Semaphore.4546struct semaphore *47sem_create(const char *name, int initial_count)48{49struct semaphore *sem;5051KASSERT(initial_count >= 0);5253sem = kmalloc(sizeof(struct semaphore));54if (sem == NULL) {55return NULL;56}5758sem->sem_name = kstrdup(name);59if (sem->sem_name == NULL) {60kfree(sem);61return NULL;62}6364sem->sem_wchan = wchan_create(sem->sem_name);65if (sem->sem_wchan == NULL) {66kfree(sem->sem_name);67kfree(sem);68return NULL;69}7071spinlock_init(&sem->sem_lock);72sem->sem_count = initial_count;7374return sem;75}7677void78sem_destroy(struct semaphore *sem)79{80KASSERT(sem != NULL);8182/* wchan_cleanup will assert if anyone's waiting on it */83spinlock_cleanup(&sem->sem_lock);84wchan_destroy(sem->sem_wchan);85kfree(sem->sem_name);86kfree(sem);87}8889void90P(struct semaphore *sem)91{92KASSERT(sem != NULL);9394/*95* May not block in an interrupt handler.96*97* For robustness, always check, even if we can actually98* complete the P without blocking.99*/100KASSERT(curthread->t_in_interrupt == false);101102spinlock_acquire(&sem->sem_lock);103while (sem->sem_count == 0) {104/*105* Bridge to the wchan lock, so if someone else comes106* along in V right this instant the wakeup can't go107* through on the wchan until we've finished going to108* sleep. Note that wchan_sleep unlocks the wchan.109*110* Note that we don't maintain strict FIFO ordering of111* threads going through the semaphore; that is, we112* might "get" it on the first try even if other113* threads are waiting. Apparently according to some114* textbooks semaphores must for some reason have115* strict ordering. Too bad. :-)116*117* Exercise: how would you implement strict FIFO118* ordering?119*/120wchan_lock(sem->sem_wchan);121spinlock_release(&sem->sem_lock);122wchan_sleep(sem->sem_wchan);123124spinlock_acquire(&sem->sem_lock);125}126KASSERT(sem->sem_count > 0);127sem->sem_count--;128spinlock_release(&sem->sem_lock);129}130131void132V(struct semaphore *sem)133{134KASSERT(sem != NULL);135136spinlock_acquire(&sem->sem_lock);137138sem->sem_count++;139KASSERT(sem->sem_count > 0);140wchan_wakeone(sem->sem_wchan);141142spinlock_release(&sem->sem_lock);143}144145////////////////////////////////////////////////////////////146//147// Lock.148149struct lock *150lock_create(const char *name)151{152struct lock *lock;153154lock = kmalloc(sizeof(struct lock));155if (lock == NULL) {156return NULL;157}158159lock->lk_name = kstrdup(name);160if (lock->lk_name == NULL) {161kfree(lock);162return NULL;163}164165lock->lk_wchan = wchan_create(lock->lk_name);166if (lock->lk_wchan == NULL) {167kfree(lock->lk_name);168kfree(lock);169return NULL;170}171spinlock_init(&lock->lk_lock);172lock->lk_holder = NULL;173174return lock;175}176177void178lock_destroy(struct lock *lock)179{180KASSERT(lock != NULL);181KASSERT(lock->lk_holder == NULL);182183spinlock_cleanup(&lock->lk_lock);184wchan_destroy(lock->lk_wchan);185186kfree(lock->lk_name);187kfree(lock);188}189190void191lock_acquire(struct lock *lock)192{193KASSERT(lock != NULL);194KASSERT(!(lock_do_i_hold(lock)));195KASSERT(curthread->t_in_interrupt == false);196197spinlock_acquire(&lock->lk_lock);198while (lock->lk_holder != NULL) {199wchan_lock(lock->lk_wchan);200spinlock_release(&lock->lk_lock);201wchan_sleep(lock->lk_wchan);202spinlock_acquire(&lock->lk_lock);203}204205lock->lk_holder = curthread;206spinlock_release(&lock->lk_lock);207}208209void210lock_release(struct lock *lock)211{212KASSERT(lock_do_i_hold(lock));213214spinlock_acquire(&lock->lk_lock);215lock->lk_holder = NULL;216wchan_wakeone(lock->lk_wchan);217spinlock_release(&lock->lk_lock);218}219220bool221lock_do_i_hold(struct lock *lock)222{223bool ret;224KASSERT(lock != NULL);225226spinlock_acquire(&lock->lk_lock);227ret = (lock->lk_holder == curthread);228spinlock_release(&lock->lk_lock);229230return ret;231}232233////////////////////////////////////////////////////////////234//235// CV236237238struct cv *239cv_create(const char *name)240{241struct cv *cv;242243cv = kmalloc(sizeof(struct cv));244if (cv == NULL) {245return NULL;246}247248cv->cv_name = kstrdup(name);249if (cv->cv_name==NULL) {250kfree(cv);251return NULL;252}253254cv->cv_wchan = wchan_create(cv->cv_name);255if (cv->cv_wchan == NULL) {256kfree(cv->cv_name);257kfree(cv);258return NULL;259}260261return cv;262}263264void265cv_destroy(struct cv *cv)266{267KASSERT(cv != NULL);268269wchan_destroy(cv->cv_wchan);270kfree(cv->cv_name);271kfree(cv);272}273274void275cv_wait(struct cv *cv, struct lock *lock)276{277KASSERT(lock_do_i_hold(lock));278279wchan_lock(cv->cv_wchan);280lock_release(lock);281wchan_sleep(cv->cv_wchan);282lock_acquire(lock);283}284285void286cv_signal(struct cv *cv, struct lock *lock)287{288KASSERT(lock_do_i_hold(lock));289290wchan_wakeone(cv->cv_wchan);291}292293void294cv_broadcast(struct cv *cv, struct lock *lock)295{296KASSERT(lock_do_i_hold(lock));297298wchan_wakeall(cv->cv_wchan);299}300301302