From a23b7fcbc2f4f986dcf2dfffc06ccde0710ba20e Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 10 Nov 2009 14:46:54 +0200 Subject: [PATCH] Task list is introduced to the thread library. In order to do resource recycling we need a table structure. In the search of one, we concluded that a task list will make things easier when we start adding COPY and NEW space handling. This commit is for utcb recycling. Now, it does not support thread trees more than one level depth. Thus, to be able to test it, we preferred l4thread_destroy instead of l4thread_exit. --- conts/libl4thread/include/l4thread/tcb.h | 35 ++++++++ conts/libl4thread/include/l4thread/thread.h | 1 + conts/libl4thread/include/l4thread/utcb.h | 7 +- conts/libl4thread/src/tcb.c | 56 ++++++++++++ conts/libl4thread/src/thread.c | 55 ++++++++++-- conts/libl4thread/src/utcb.c | 95 +++++++++++++++------ 6 files changed, 211 insertions(+), 38 deletions(-) create mode 100644 conts/libl4thread/include/l4thread/tcb.h create mode 100644 conts/libl4thread/src/tcb.c 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) {}*/ -