#include <defs.h>
|
|
#include <wait.h>
|
|
#include <atomic.h>
|
|
#include <kmalloc.h>
|
|
#include <sem.h>
|
|
#include <proc.h>
|
|
#include <sync.h>
|
|
#include <assert.h>
|
|
|
|
void
|
|
sem_init(semaphore_t *sem, int value) {
|
|
sem->value = value;
|
|
wait_queue_init(&(sem->wait_queue));
|
|
}
|
|
|
|
static __noinline void __up(semaphore_t *sem, uint32_t wait_state) {
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
wait_t *wait;
|
|
if ((wait = wait_queue_first(&(sem->wait_queue))) == NULL) {
|
|
sem->value ++;
|
|
}
|
|
else {
|
|
assert(wait->proc->wait_state == wait_state);
|
|
wakeup_wait(&(sem->wait_queue), wait, wait_state, 1);
|
|
}
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|
|
|
|
static __noinline uint32_t __down(semaphore_t *sem, uint32_t wait_state) {
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
if (sem->value > 0) {
|
|
sem->value --;
|
|
local_intr_restore(intr_flag);
|
|
return 0;
|
|
}
|
|
wait_t __wait, *wait = &__wait;
|
|
wait_current_set(&(sem->wait_queue), wait, wait_state);
|
|
local_intr_restore(intr_flag);
|
|
|
|
schedule();
|
|
|
|
local_intr_save(intr_flag);
|
|
wait_current_del(&(sem->wait_queue), wait);
|
|
local_intr_restore(intr_flag);
|
|
|
|
if (wait->wakeup_flags != wait_state) {
|
|
return wait->wakeup_flags;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
up(semaphore_t *sem) {
|
|
__up(sem, WT_KSEM);
|
|
}
|
|
|
|
void
|
|
down(semaphore_t *sem) {
|
|
uint32_t flags = __down(sem, WT_KSEM);
|
|
assert(flags == 0);
|
|
}
|
|
|
|
bool
|
|
try_down(semaphore_t *sem) {
|
|
bool intr_flag, ret = 0;
|
|
local_intr_save(intr_flag);
|
|
if (sem->value > 0) {
|
|
sem->value --, ret = 1;
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
return ret;
|
|
}
|
|
|