metalsvm/include/metalsvm/semaphore.h
2010-08-09 17:31:11 +00:00

132 lines
2.5 KiB
C

/*
* Copyright 2010 Stefan Lankes, Chair for Operating Systems,
* RWTH Aachen University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of MetalSVM.
*/
#ifndef __SEMAPHORE_H__
#define __SEMAPHORE_H__
#include <metalsvm/string.h>
#include <metalsvm/tasks.h>
#include <metalsvm/spinlock.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned int value;
tid_t queue[MAX_TASKS];
unsigned int pos;
spinlock_t lock;
} sem_t;
#define SEM_INIT(v) {v, {[0 ... MAX_TASKS-1] = MAX_TASKS}, 0, SPINLOCK_INIT};
inline static int sem_init(sem_t* s, unsigned int v) {
unsigned int i;
if (BUILTIN_EXPECT(!s, 0))
return -1;
s->value = v;
s->pos = 0;
for(i=0; i<MAX_TASKS; i++)
s->queue[i] = MAX_TASKS;
spinlock_init(&s->lock);
return 0;
}
inline static int sem_destroy(sem_t* s) {
if (BUILTIN_EXPECT(!s, 0))
return -1;
spinlock_destroy(&s->lock);
return 0;
}
inline static int sem_wait(sem_t* s) {
if (BUILTIN_EXPECT(!s, 0))
return -1;
next_try:
spinlock_lock(&s->lock);
if (s->value > 0) {
s->value--;
spinlock_unlock(&s->lock);
} else {
s->queue[s->pos] = current_task->id;
s->pos = (s->pos + 1) % MAX_TASKS;
block_task(current_task->id);
spinlock_unlock(&s->lock);
reschedule();
goto next_try;
}
return 0;
}
inline static int sem_trywait(sem_t* s) {
int ret = -1;
if (BUILTIN_EXPECT(!s, 0))
return -1;
spinlock_lock(&s->lock);
if (s->value > 0) {
s->value--;
ret = 0;
}
spinlock_unlock(&s->lock);
return ret;
}
inline static int sem_post(sem_t* s) {
if (BUILTIN_EXPECT(!s, 0))
return -1;
spinlock_lock(&s->lock);
if (s->value > 0) {
s->value++;
spinlock_unlock(&s->lock);
} else {
unsigned int k, i;
s->value++;
i = s->pos;
for(k=0; k<MAX_TASKS; k++) {
if (s->queue[i] < MAX_TASKS) {
wakeup_task(s->queue[i]);
s->queue[i] = MAX_TASKS;
break;
}
i = (i + 1) % MAX_TASKS;
}
spinlock_unlock(&s->lock);
}
return 0;
}
#ifdef __cplusplus
}
#endif
#endif