diff --git a/include/metalsvm/tasks_types.h b/include/metalsvm/tasks_types.h index 5a028e33..e448e07f 100644 --- a/include/metalsvm/tasks_types.h +++ b/include/metalsvm/tasks_types.h @@ -37,13 +37,14 @@ extern "C" { typedef void* (STDCALL *entry_point_t)(void*); typedef unsigned int tid_t; -typedef struct { +typedef struct task { unsigned char* top; unsigned int ip; tid_t id; mm_t mm; unsigned char* stack; size_t stack_size; + unsigned char blocked_tasks[MAX_TASKS]; unsigned char status; unsigned char idle; } task_t; diff --git a/kernel/main.c b/kernel/main.c index dd6ae482..eb57cdda 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -42,6 +42,18 @@ void* STDCALL foo(void* arg) return NULL; } +void* STDCALL join_test(void* arg) +{ + int ret; + tid_t id; + + ret = create_kernel_task(&id, foo, "Hello from foo2\n", 0); + kprintf("Wait for task %u: ret = %d\n", id, ret); + ret = join_kernel_task(id); + kprintf("Task %u finished: ret = %d\n", id, ret); + + return NULL; +} int main(void) { @@ -70,7 +82,7 @@ int main(void) timer_set_frequency(TIMER_FREQ); create_kernel_task(&id1, foo, "Hello from foo1\n", 8192); - create_kernel_task(&id2, foo, "Hello from foo2\n", 0); + create_kernel_task(&id2, join_test, NULL, 0); current_task->idle = 1; schedule(); diff --git a/kernel/tasks.c b/kernel/tasks.c index f6e2e282..73fbadca 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -92,6 +92,7 @@ int create_kernel_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size task_table[i].top = task_table[i].stack + stack_size - sizeof(size_t); task_table[i].ip = 0; task_table[i].id = i; + memset(task_table[i].blocked_tasks, 0x00, sizeof(unsigned char)*MAX_TASKS); task_table[i].status = TASK_READY; task_table[i].idle = 0; @@ -110,7 +111,42 @@ int create_kernel_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size int join_kernel_task(tid_t id) { - return -1; + int ret = -1; + + irq_disable(); + + /* + * idle tasks are not allowed to wait for another task + * they should always run... + */ + if (BUILTIN_EXPECT(current_task->idle, 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) @@ -118,9 +154,17 @@ task_t* get_new_task(void) unsigned int i, new_id; /* signalize that this task could be reuse */ - if (current_task->status == TASK_FINISHED) + 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;