diff --git a/conts/libl4thread/include/l4thread/tcb.h b/conts/libl4thread/include/l4thread/tcb.h new file mode 100644 index 0000000..1c81111 --- /dev/null +++ b/conts/libl4thread/include/l4thread/tcb.h @@ -0,0 +1,35 @@ +/* + * Thread control block. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __LIB_TCB_H__ +#define __LIB_TCB_H__ + +#include + +/* Keeps all the struct utcb_descs belonging to a thread group together. */ +struct utcb_head { + struct link list; +}; + +/* A simple thread control block for the thread library. */ +struct l4t_tcb { + struct link list; + int tid; + struct utcb_head *utcb_head; + unsigned long utcb_addr; +}; + +/* This struct keeps track of all the threads handled by the thread lib. */ +struct l4t_global_list { + int total; + struct link list; +}; + +struct l4t_tcb *l4t_find_task(int tid); +struct l4t_tcb *l4t_tcb_alloc_init(struct l4t_tcb *parent, unsigned int flags); +void l4t_global_add_task(struct l4t_tcb *task); +void l4t_global_remove_task(struct l4t_tcb *task); + +#endif /* __LIB_TCB_H__ */ diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index c1ce0a9..319233e 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -13,5 +13,6 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); int l4thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); +void l4thread_kill(struct task_ids *ids); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h index 32049e5..f16f310 100644 --- a/conts/libl4thread/include/l4thread/utcb.h +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -6,10 +6,9 @@ #ifndef __LIB_UTCB_H__ #define __LIB_UTCB_H__ -#define IS_UTCB_SETUP() (udesc_ptr) +#include -struct utcb_desc *udesc_ptr; - -unsigned long get_utcb_addr(void); +unsigned long get_utcb_addr(struct l4t_tcb *task); +int delete_utcb_addr(struct l4t_tcb *task); #endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/tcb.c b/conts/libl4thread/src/tcb.c new file mode 100644 index 0000000..d0125bb --- /dev/null +++ b/conts/libl4thread/src/tcb.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + +/* Global task list. */ +struct l4t_global_list l4t_global_tasks = { + .list = { &l4t_global_tasks.list, &l4t_global_tasks.list }, + .total = 0, +}; + +/* Function definitions */ +void l4t_global_add_task(struct l4t_tcb *task) +{ + BUG_ON(!list_empty(&task->list)); + list_insert_tail(&task->list, &l4t_global_tasks.list); + l4t_global_tasks.total++; +} + +void l4t_global_remove_task(struct l4t_tcb *task) +{ + BUG_ON(list_empty(&task->list)); + list_remove_init(&task->list); + BUG_ON(--l4t_global_tasks.total < 0); +} + +struct l4t_tcb *l4t_find_task(int tid) +{ + struct l4t_tcb *t; + + list_foreach_struct(t, &l4t_global_tasks.list, list) + if (t->tid == tid) + return t; + return 0; +} + +struct l4t_tcb *l4t_tcb_alloc_init(struct l4t_tcb *parent, unsigned int flags) +{ + struct l4t_tcb *task; + + if (!(task = kzalloc(sizeof(struct l4t_tcb)))) + return PTR_ERR(-ENOMEM); + + link_init(&task->list); + + if ((parent) && (flags & TC_SHARE_SPACE)) + task->utcb_head = parent->utcb_head; + else { + if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) + return PTR_ERR(-ENOMEM); + link_init(&task->utcb_head->list); + } + + return task; +} diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index 19b856e..87e84b4 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -8,6 +8,7 @@ #include #include #include +#include #include /* Symbolic constants and macros */ @@ -72,10 +73,12 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, { struct exregs_data exregs; unsigned long utcb_addr; + struct l4t_tcb *parent, *child; int err; /* A few controls before granting access to thread creation */ - if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { + // FIXME: check if utcb region is setup + if (!IS_STACK_SETUP()) { printf("libl4thread: Stack and/or utcb have not been " "set up.\n"); return -EPERM; @@ -87,6 +90,8 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return -ENOMEM; } + // FIXME: Check if there is enough utcb space + if (!(TC_SHARE_SPACE & flags)) { printf("libl4thread: Only allows shared space thread " "creation.\n"); @@ -94,19 +99,32 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return -EINVAL; } - /* Get a utcb addr for this thread */ - if (!(utcb_addr = get_utcb_addr())) { - printf("libl4thread: No utcb address left.\n"); + /* Get parent's ids and find the tcb belonging to it. */ + l4_getid(ids); + if (!(parent = l4t_find_task(ids->tid))) + return-ESRCH; + + /* Allocate tcb for the child. */ + if (!(child = l4t_tcb_alloc_init(parent, flags))) { + printf("libl4thread: No heap space left.\n"); return -ENOMEM; } - /* Get parent's ids */ - l4_getid(ids); + /* Get a utcb addr for this thread */ + if (!(utcb_addr = get_utcb_addr(child))) { + printf("libl4thread: No utcb address left.\n"); + // FIXME: Check if there is any memory leak + kfree(child); + return -ENOMEM; + } /* Create thread */ if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_CREATE) " "failed with (%d).\n", err); + // FIXME: Check if there is any memory leak + kfree(child); + delete_utcb_addr(child); return err; } @@ -119,6 +137,7 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " "(%d).\n", err); + // FIXME: Check if there is any memory leak return err; } @@ -131,6 +150,10 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, /* Update the stack address */ lib_stack_bot_addr -= lib_stack_size; + /* Add child to the global task list */ + child->tid = ids->tid; + l4t_global_add_task(child); + /* Start the new thread */ if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_RUN) " @@ -140,3 +163,23 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return 0; } + +void l4thread_kill(struct task_ids *ids) +{ + struct l4t_tcb *task; + + /* Find the task to be killed. */ + task = l4t_find_task(ids->tid); + + /* Delete the utcb address. */ + delete_utcb_addr(task); + + /* Remove child from the global task list. */ + l4t_global_remove_task(task); + + // FIXME: We assume that main thread never leaves the scene + kfree(task); + + /* Finally, destroy the thread. */ + l4_thread_control(THREAD_DESTROY, ids); +} diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 049bcbe..4dd7fef 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -8,43 +8,86 @@ #include #include #include +#include #include #include -/* Static variable definitions */ -static unsigned long lib_utcb_end_addr; +/* Extern declarations */ +extern struct l4t_global_list l4t_global_tasks; /* Function definitions */ -unsigned long get_utcb_addr(void) +unsigned long get_utcb_addr(struct l4t_tcb *task) { - unsigned long utcb_addr; + struct utcb_desc *udesc; + unsigned long slot; - if (!(utcb_addr = utcb_new_slot(udesc_ptr))) { - udesc_ptr = utcb_new_desc(); - utcb_addr = utcb_new_slot(udesc_ptr); + /* Setting this up twice is a bug. */ + BUG_ON(task->utcb_addr); + + /* Search for an empty utcb slot already allocated to this space. */ + list_foreach_struct(udesc, &task->utcb_head->list, list) + if ((slot = utcb_new_slot(udesc))) + goto found; + + /* Allocate a new utcb memory region and return its base. */ + udesc = utcb_new_desc(); + slot = utcb_new_slot(udesc); + list_insert(&udesc->list, &task->utcb_head->list); +found: + task->utcb_addr = slot; + + return slot; +} + +int delete_utcb_addr(struct l4t_tcb *task) +{ + struct utcb_desc *udesc; + + list_foreach_struct(udesc, &task->utcb_head->list, list) { + /* FIXME: Use variable alignment than a page */ + /* Detect matching slot */ + if (page_align(task->utcb_addr) == udesc->utcb_base) { + + /* Delete slot from the descriptor */ + utcb_delete_slot(udesc, task->utcb_addr); + + /* Is the desc completely empty now? */ + if (id_is_empty(udesc->slots)) { + /* Unlink desc from its list */ + list_remove_init(&udesc->list); + /* Delete the descriptor */ + utcb_delete_desc(udesc); + } + return 0; /* Finished */ + } } - - if (utcb_addr >= lib_utcb_end_addr) - return 0; - - return utcb_addr; + BUG(); } static int set_utcb_addr(void) { struct exregs_data exregs; - unsigned long utcb_addr; struct task_ids ids; + struct l4t_tcb *task; + struct utcb_desc *udesc; int err; - l4_getid(&ids); - // FIXME: its tid must be 0. - udesc_ptr = utcb_new_desc(); - utcb_addr = get_utcb_addr(); + /* Create a task. */ + if (IS_ERR(task = l4t_tcb_alloc_init(0, 0))) + return -ENOMEM; + + /* Add child to the global task list. */ + list_insert_tail(&task->list, &l4t_global_tasks.list); + l4t_global_tasks.total++; + + udesc = utcb_new_desc(); + task->utcb_addr = utcb_new_slot(udesc); + list_insert(&udesc->list, &task->utcb_head->list); memset(&exregs, 0, sizeof(exregs)); - exregs_set_utcb(&exregs, (unsigned long)utcb_addr); + exregs_set_utcb(&exregs, (unsigned long)task->utcb_addr); + l4_getid(&ids); if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " "(%d).\n", err); @@ -59,11 +102,12 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) int err; /* Ensure that arguments are valid. */ - if (IS_UTCB_SETUP()) { - printf("libl4thread: You have already called: %s.\n", - __FUNCTION__); - return -EPERM; - } + // FIXME: Check if set_utcb_params is called + /*if (IS_UTCB_SETUP()) {*/ + /*printf("libl4thread: You have already called: %s.\n",*/ + /*__FUNCTION__);*/ + /*return -EPERM;*/ + /*}*/ if (!utcb_start || !utcb_end) { printf("libl4thread: Utcb address range cannot contain " "0x0 as a start and/or end address(es).\n"); @@ -96,14 +140,9 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) /* Init utcb virtual address pool */ utcb_pool_init(utcb_start, utcb_end); - lib_utcb_end_addr = utcb_end; - /* The very first thread's utcb address is assigned. */ if ((err = set_utcb_addr()) < 0) return err; return 0; } - -/*void destroy_utcb(void) {}*/ -