- add an implementation of a semaphore and some test cases

git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@18 315a16e6-25f9-4109-90ae-ca3045a26c18
This commit is contained in:
stefan 2010-08-02 19:05:33 +00:00
parent b6375e8d6c
commit 44f4de6e80
5 changed files with 152 additions and 4 deletions

View file

@ -41,7 +41,7 @@ void schedule_entry(void);
*/
static void timer_handler(struct regs *r)
{
unsigned int tmp;
//unsigned int tmp;
/* Increment our 'tick counter' */
timer_ticks++;
@ -50,10 +50,10 @@ static void timer_handler(struct regs *r)
* Every TIMER_FREQ clocks (approximately 1 second), we will
* display a message on the screen
*/
tmp = (unsigned int) (timer_ticks & 0xFFFFFFFF);
/*tmp = (unsigned int) (timer_ticks & 0xFFFFFFFF);
if (tmp % TIMER_FREQ == 0) {
kputs("One second has passed\n");
}
}*/
if (current_task && !(current_task->ip)) {
current_task->ip = r->eip;

View file

@ -0,0 +1,98 @@
/*
* 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/spinlocks.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned int value;
tid_t queue[MAX_TASKS];
unsigned int pos;
spinlock_t lock;
} sem_t;
inline static void sem_init(sem_t* s, unsigned int v) {
unsigned int i;
s->value = v;
s->pos = 0;
for(i=0; i<MAX_TASKS; i++)
s->queue[i] = MAX_TASKS;
spinlock_init(&s->lock);
}
inline static void sem_destroy(sem_t* s) {
spinlock_destroy(&s->lock);
}
inline static int sem_wait(sem_t* s) {
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;
current_task->status = TASK_BLOCKED;
spinlock_unlock(&s->lock);
schedule();
goto next_try;
}
return 0;
}
inline static int sem_post(sem_t* s) {
spinlock_lock(&s->lock);
if (s->value > 0) {
s->value++;
spinlock_unlock(&s->lock);
} else {
unsigned int k, i;
i = s->pos;
s->value++;
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

View file

@ -36,6 +36,7 @@ int create_kernel_task(tid_t*, entry_point_t, void*, size_t);
int join_kernel_task(tid_t);
void schedule(void);
task_t* get_new_task(void);
int wakeup_task(tid_t);
#ifdef __cplusplus
}

View file

@ -25,8 +25,40 @@
#include <metalsvm/mmu.h>
#include <metalsvm/tasks.h>
#include <metalsvm/processor.h>
#include <metalsvm/semaphore.h>
#include <asm/kb.h>
static sem_t consuming, producing;
static int val = 0;
void* STDCALL producer(void* arg)
{
int i;
for(i=0; i<5; i++) {
sem_wait(&producing);
kprintf("Produce value: current val %d\n", val);
val = 42;
sem_post(&consuming);
}
return NULL;
}
void* STDCALL consumer(void* arg)
{
int i;
for(i=0; i<5; i++) {
sem_wait(&consuming);
kprintf("Consumer got %d\n", val);
val = 0;
sem_post(&producing);
}
return NULL;
}
void* STDCALL foo(void* arg)
{
int i;
@ -57,7 +89,7 @@ void* STDCALL join_test(void* arg)
int main(void)
{
tid_t id1, id2;
tid_t id1, id2, id3, id4;
system_init();
irq_init();
@ -81,8 +113,13 @@ int main(void)
timer_set_frequency(TIMER_FREQ);
sem_init(&producing, 1);
sem_init(&consuming, 0);
create_kernel_task(&id1, foo, "Hello from foo1\n", 8192);
create_kernel_task(&id2, join_test, NULL, 0);
create_kernel_task(&id3, producer, NULL, 0);
create_kernel_task(&id4, consumer, NULL, 0);
current_task->idle = 1;
schedule();

View file

@ -149,6 +149,18 @@ out:
return ret;
}
int wakeup_task(tid_t id)
{
if (task_table[id].status != TASK_BLOCKED) {
kprintf("Task %u is already unblocked\n", id);
return -1;
}
task_table[id].status = TASK_READY;
return 0;
}
task_t* get_new_task(void)
{
unsigned int i, new_id;