/* * synch.c * * Sung-Eun Choi (sungeun@cs.washington.edu) * Autumn 1996 * */ #include #include "my_malloc.h" #include "minithread.h" #include "minithread_export.h" #include "queue.h" #include "synch.h" #include "spinlock.h" #ifdef DEBUG_MT #include "panic.h" #define semaphore_panic panic #endif /* * A semaphore should be defined either in this file or in a private * header file. */ struct semaphore { int count; queue_t waiters; tas_lock_t mutex; }; /* * Semaphores. */ /* * semaphore_t semaphore_create() * Allocate a new semaphore. */ semaphore_t semaphore_create() { semaphore_t s; s = (semaphore_t) my_malloc(sizeof(struct semaphore)); s->count = 0; s->waiters = queue_new(); spinlock_init(&(s->mutex)); #ifdef DEBUG_MT printf("created semaphore 0x%x\n", s); fflush(stdout); #endif return s; } /* * semaphore_destroy(semaphore_t sem); * Deallocate a semaphore. */ void semaphore_destroy(semaphore_t s) { minithread_t t; if (s != NULL) { disable_interrupts(); queue_dequeue(s->waiters, (any_t *) &t); while (t != NULL) { /* remove all the waiters */ #ifdef DEBUG_MT printf("semaphore_destroy: destroying minithread 0x%x\n", t); fflush(stdout); #endif minithread_destroy(t); queue_dequeue(s->waiters, (any_t *) &t); } queue_free(s->waiters); my_free(s); enable_interrupts(); } } /* * semaphore_initialize(semaphore_t sem, int cnt) * initialize the semaphore data structure pointed at by * sem with an initial value cnt. */ void semaphore_initialize(semaphore_t s, int count) { spinlock_lock(&s->mutex); /* get the lock */ s->count = count; /* reset the count */ spinlock_unlock(&s->mutex); /* release the lock */ } /* * semaphore_P(semaphore_t sem) * P (wait) on the sempahore. */ void semaphore_P(semaphore_t s) { spinlock_lock(&s->mutex); /* get the lock */ if (s->count == 0) { /* this process must wait */ #ifdef DEBUG_MT printf("enqueuing thread 0x%x on semaphore 0x%x\n", minithread_self(), s); fflush(stdout); #endif queue_append(s->waiters, (any_t) minithread_self()); /* release the lock and stop */ minithread_unlock_and_stop(&s->mutex); } else if (s->count > 0) { /* this process may enter */ s->count--; spinlock_unlock(&s->mutex); /* release the lock */ } #ifdef DEBUG_MT else { semaphore_panic("Error in semaphore value."); } #endif } /* * semaphore_V(semaphore_t sem) * V (signal) on the sempahore. */ void semaphore_V(semaphore_t s) { minithread_t t; spinlock_lock(&s->mutex); /* get the lock */ if (s->count == 0) { queue_dequeue(s->waiters, (any_t *) &t); if (t != NULL) { #ifdef DEBUG_MT if (t == minithread_self()) { semaphore_panic("Error in semaphore queue."); } printf("thread 0x%x dequeued 0x%x on semaphore 0x%x\n", minithread_self(), t, s); fflush(stdout); #endif minithread_start(t); /* start a waiting thread */ } else { s->count++; /* increment the counter */ } } else if (s->count > 0) { s->count++; /* increment the counter */ } #ifdef DEBUG_MT else { semaphore_panic("Error in semaphore value."); } #endif spinlock_unlock(&s->mutex); /* release the lock */ }