/* * 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. */ #include #include #include #include #include #include #include task_t* current_task = NULL; static task_t task_table[MAX_TASKS]; int multitasking_init(void) { memset(task_table, 0, sizeof(task_t)*MAX_TASKS); task_table[0].id = 0; task_table[0].mm.usage = 0; task_table[0].stack = NULL; task_table[0].stack_size = 8192; task_table[0].status = TASK_RUNNING; task_table[0].idle = 0; current_task = task_table; return 0; } void NORETURN leave_task(void) { kprintf("Terminate task: %u\n", current_task->id); current_task->status = TASK_FINISHED; schedule(); kputs("Kernel panic: scheduler found no valid task\n"); while(1) { NOP8; } } void NORETURN abort(void) { kprintf("Abbort task: %u\n", current_task->id); current_task->status = TASK_FINISHED; schedule(); kputs("Kernel panic: scheduler found no valid task\n"); while(1) { NOP8; } } int create_kernel_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size) { int ret = -1; unsigned int i; if (BUILTIN_EXPECT(!ep, 0)) return -1; if (!stack_size) stack_size = DEFAULT_STACK_SIZE; irq_disable(); for(i=0; iidle, 0)) goto out; /* a task is not able to wait for itself */ if (BUILTIN_EXPECT(current_task->id == id, 0)) goto out; /* invalid id */ if (BUILTIN_EXPECT(id >= MAX_TASKS, 0)) goto out; ret = 0; /* task already finished */ if (BUILTIN_EXPECT(task_table[id].status == TASK_INVALID, 0)) goto out; /* task already finished */ if (BUILTIN_EXPECT(task_table[id].status == TASK_FINISHED, 0)) goto out; task_table[id].blocked_tasks[current_task->id] = 1; current_task->status = TASK_BLOCKED; out: irq_enable(); schedule(); return ret; } task_t* get_new_task(void) { unsigned int i, new_id; /* signalize that this task could be reuse */ if (current_task->status == TASK_FINISHED) { current_task = TASK_INVALID; /* wake up blocked tasks */ for(i=0; iblocked_tasks[i]) && (task_table[i].status == TASK_BLOCKED)) task_table[i].status = TASK_READY; current_task->blocked_tasks[i] = 0; } } for(i=1; i <= MAX_TASKS; i++) { new_id = (current_task->id + i) % MAX_TASKS; if (!task_table[new_id].idle && task_table[new_id].status == TASK_READY) { if (current_task->status == TASK_RUNNING) current_task->status = TASK_READY; task_table[new_id].status = TASK_RUNNING; return task_table+new_id; } } if (!(current_task->idle) && (current_task->status == TASK_RUNNING)) return current_task; /* * we switch to the idle task (id=0), if the current task terminates * and no other is ready */ task_table[0].status = TASK_RUNNING; return task_table+0; }