diff --git a/arch/x86/kernel/timer.c b/arch/x86/kernel/timer.c index 1acf1fb1..4b3b2fd4 100644 --- a/arch/x86/kernel/timer.c +++ b/arch/x86/kernel/timer.c @@ -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; diff --git a/include/metalsvm/semaphore.h b/include/metalsvm/semaphore.h new file mode 100644 index 00000000..9d7750a1 --- /dev/null +++ b/include/metalsvm/semaphore.h @@ -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 +#include +#include + +#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; iqueue[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; kqueue[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 diff --git a/include/metalsvm/tasks.h b/include/metalsvm/tasks.h index c88c8228..fb89eb77 100644 --- a/include/metalsvm/tasks.h +++ b/include/metalsvm/tasks.h @@ -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 } diff --git a/kernel/main.c b/kernel/main.c index eb57cdda..e45f5fef 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -25,8 +25,40 @@ #include #include #include +#include #include +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(); diff --git a/kernel/tasks.c b/kernel/tasks.c index 69514755..c5b9860e 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -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;