metalsvm/include/metalsvm/semaphore.h
2011-04-04 18:12:08 +02:00

166 lines
3.1 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.
*/
/**
* @author Stefan Lankes
* @file include/metalsvm/semaphore.h
* @brief semaphore functions definition
*/
#ifndef __SEMAPHORE_H__
#define __SEMAPHORE_H__
#include <metalsvm/string.h>
#include <metalsvm/semaphore_types.h>
#include <metalsvm/spinlock.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Semaphore initialization
*
* Always init semaphores before use!
*
* @param s Pointer to semaphore structure to initialize
* @param v Resource count
*
* @return
* - 0 on success
* - -1 on failure
*/
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;
}
/** @brief Destroy semaphore
* @return
* - 0 on success
* - -1 on failure
*/
inline static int sem_destroy(sem_t* s) {
if (BUILTIN_EXPECT(!s, 0))
return -1;
spinlock_destroy(&s->lock);
return 0;
}
/** @brief Blocking wait for semaphore
*
* This will put your task to sleep
*
* @return
* - 0 on success
* - -1 on failure
*/
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] = per_core(current_task)->id;
s->pos = (s->pos + 1) % MAX_TASKS;
block_task(per_core(current_task)->id);
spinlock_unlock(&s->lock);
reschedule();
goto next_try;
}
return 0;
}
/** @brief Nonblocking trywait for sempahore
*
* Will return immediately if not available
*
* @return
* - 0 on success (You got the semaphore)
* - -1 on failure (You still have to wait)
*/
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;
}
/** @brief Give back resource
* @return
* - 0 on success
* - -1 on failure
*/
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