From 743034a36b6a7ae0bfb631be53bd0a913b93c719 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 12 Nov 2009 22:29:41 +0200 Subject: [PATCH] A comprehensive overhaul on the thread library. Lots of polishing, organizational changes, bug fixes, error handling etc. are introduced. COPY and NEW space thread creation are allowed but not thoroughly tested yet. It seems they will work best if the lib supports utcb virtual range management through the mapping. --- conts/libl4thread/include/l4thread/addr.h | 2 +- conts/libl4thread/include/l4thread/stack.h | 8 +- conts/libl4thread/include/l4thread/tcb.h | 21 ++- conts/libl4thread/include/l4thread/thread.h | 4 +- conts/libl4thread/include/l4thread/utcb.h | 9 +- conts/libl4thread/src/idpool.c | 3 +- conts/libl4thread/src/stack.c | 21 ++- conts/libl4thread/src/tcb.c | 38 +++--- conts/libl4thread/src/thread.c | 134 +++++++++++--------- conts/libl4thread/src/utcb-common.c | 8 +- conts/libl4thread/src/utcb.c | 60 +++++---- 11 files changed, 177 insertions(+), 131 deletions(-) diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h index 900d790..8182ec0 100644 --- a/conts/libl4thread/include/l4thread/addr.h +++ b/conts/libl4thread/include/l4thread/addr.h @@ -1,5 +1,5 @@ /* - * Address allocation pool + * Address allocation pool. * * Copyright (C) 2007 Bahadir Balban */ diff --git a/conts/libl4thread/include/l4thread/stack.h b/conts/libl4thread/include/l4thread/stack.h index 6f382e2..d0e5f09 100644 --- a/conts/libl4thread/include/l4thread/stack.h +++ b/conts/libl4thread/include/l4thread/stack.h @@ -1,19 +1,19 @@ /* - * Stack region helper routines. + * Stack space helper routines. * * Copyright (C) 2009 B Labs Ltd. */ #ifndef __LIB_STACK_H__ #define __LIB_STACK_H__ -/* Symbolic constants and macros */ +/* Checks if l4_set_stack_params is called. */ #define IS_STACK_SETUP() (lib_stack_size) int stack_pool_init(unsigned long stack_start, unsigned long stack_end, unsigned long stack_size); -void *get_stack_space(int nitems, int size); -int delete_stack_space(void *stack_address, int nitems, int size); +void *get_stack_space(void); +int delete_stack_space(void *stack_address); #endif /* __LIB_STACK_H__ */ diff --git a/conts/libl4thread/include/l4thread/tcb.h b/conts/libl4thread/include/l4thread/tcb.h index a2f399e..da332e0 100644 --- a/conts/libl4thread/include/l4thread/tcb.h +++ b/conts/libl4thread/include/l4thread/tcb.h @@ -14,23 +14,30 @@ struct utcb_head { }; /* A simple thread control block for the thread library. */ -struct l4t_tcb { +struct tcb { + /* Task list */ struct link list; + + /* Task id */ int tid; + + /* Chain of utcb descriptors */ struct utcb_head *utcb_head; + + /* Stack and utcb address */ unsigned long utcb_addr; unsigned long stack_addr; }; -/* This struct keeps track of all the threads handled by the thread lib. */ -struct l4t_global_list { +/* All the threads handled by the thread lib are kept in this list. */ +struct 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); +struct tcb *find_task(int tid); +struct tcb *tcb_alloc_init(struct tcb *parent, unsigned int flags); +void global_add_task(struct tcb *task); +void global_remove_task(struct tcb *task); #endif /* __LIB_TCB_H__ */ diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 77246e3..8cd3125 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -12,7 +12,7 @@ int l4_set_stack_params(unsigned long stack_top, int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); int l4_thread_create(struct task_ids *ids, unsigned int flags, - void *(*func)(void *), void *arg); -void l4_thread_exit(void *retval); + int (*func)(void *), void *arg); +void l4_thread_exit(int retval); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h index f16f310..086aa93 100644 --- a/conts/libl4thread/include/l4thread/utcb.h +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -1,5 +1,5 @@ /* - * UTCB handling helper routines + * UTCB handling helper routines. * * Copyright (C) 2009 B Labs Ltd. */ @@ -8,7 +8,10 @@ #include -unsigned long get_utcb_addr(struct l4t_tcb *task); -int delete_utcb_addr(struct l4t_tcb *task); +/* Checks if l4_set_stack_params is called. */ +#define IS_UTCB_SETUP() (lib_utcb_range_size) + +unsigned long get_utcb_addr(struct tcb *task); +int delete_utcb_addr(struct tcb *task); #endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/idpool.c b/conts/libl4thread/src/idpool.c index 423ac33..17fd450 100644 --- a/conts/libl4thread/src/idpool.c +++ b/conts/libl4thread/src/idpool.c @@ -1,5 +1,6 @@ /* - * Used for thread and space ids, and also for utcbs. + * Used for thread and space ids, and also for + * utcb tracking in page-sized-chunks. * * Copyright (C) 2009 B Labs Ltd. */ diff --git a/conts/libl4thread/src/stack.c b/conts/libl4thread/src/stack.c index 36b86b8..5fedcba 100644 --- a/conts/libl4thread/src/stack.c +++ b/conts/libl4thread/src/stack.c @@ -35,14 +35,14 @@ int stack_pool_init(unsigned long stack_start, return 0; } -void *get_stack_space(int nitems, int size) +void *get_stack_space(void) { - return address_new(&stack_region_pool, nitems, size); + return address_new(&stack_region_pool, 1, lib_stack_size); } -int delete_stack_space(void *stack_address, int nitems, int size) +int delete_stack_space(void *stack_address) { - return address_del(&stack_region_pool, stack_address, nitems, size); + return address_del(&stack_region_pool, stack_address, 1, lib_stack_size); } int l4_set_stack_params(unsigned long stack_top, @@ -50,11 +50,9 @@ int l4_set_stack_params(unsigned long stack_top, unsigned long stack_size) { /* Ensure that arguments are valid. */ - // FIXME: Check if lib_stack_size is convenient to use - // for ensuring stack space is setup. if (IS_STACK_SETUP()) { printf("libl4thread: You have already called: %s.\n", - __FUNCTION__); + __FUNCTION__); return -EPERM; } if (!stack_top || !stack_bottom) { @@ -87,12 +85,11 @@ int l4_set_stack_params(unsigned long stack_top, /* Initialize internal variables. */ lib_stack_size = stack_size; - /* Init stack virtual address pool. */ - stack_pool_init(stack_top, stack_bottom, stack_size); + /* Initialize stack virtual address pool. */ + if (stack_pool_init(stack_top, stack_bottom, stack_size) < 0) + BUG(); - /* Init the global mutex. */ - //FIXME: Ensure that l4thread_create will not be called - // before the mutex is initialized. + /* Initialize the global mutex. */ l4_mutex_init(&lib_mutex); return 0; diff --git a/conts/libl4thread/src/tcb.c b/conts/libl4thread/src/tcb.c index d0125bb..dec4918 100644 --- a/conts/libl4thread/src/tcb.c +++ b/conts/libl4thread/src/tcb.c @@ -1,3 +1,8 @@ +/* + * Thread management in libl4thread. + * + * Copyright (C) 2009 B Labs Ltd. + */ #include #include #include @@ -5,50 +10,53 @@ #include /* Global task list. */ -struct l4t_global_list l4t_global_tasks = { - .list = { &l4t_global_tasks.list, &l4t_global_tasks.list }, +struct global_list global_tasks = { + .list = { &global_tasks.list, &global_tasks.list }, .total = 0, }; /* Function definitions */ -void l4t_global_add_task(struct l4t_tcb *task) +void global_add_task(struct tcb *task) { BUG_ON(!list_empty(&task->list)); - list_insert_tail(&task->list, &l4t_global_tasks.list); - l4t_global_tasks.total++; + list_insert_tail(&task->list, &global_tasks.list); + global_tasks.total++; } -void l4t_global_remove_task(struct l4t_tcb *task) +void global_remove_task(struct tcb *task) { BUG_ON(list_empty(&task->list)); list_remove_init(&task->list); - BUG_ON(--l4t_global_tasks.total < 0); + BUG_ON(--global_tasks.total < 0); } -struct l4t_tcb *l4t_find_task(int tid) +struct tcb *find_task(int tid) { - struct l4t_tcb *t; + struct tcb *t; - list_foreach_struct(t, &l4t_global_tasks.list, list) + list_foreach_struct(t, &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 tcb *tcb_alloc_init(struct tcb *parent, unsigned int flags) { - struct l4t_tcb *task; + struct tcb *task; - if (!(task = kzalloc(sizeof(struct l4t_tcb)))) + if (!(task = kzalloc(sizeof(struct tcb)))) return PTR_ERR(-ENOMEM); link_init(&task->list); - if ((parent) && (flags & TC_SHARE_SPACE)) + if (flags & TC_SHARE_SPACE) task->utcb_head = parent->utcb_head; else { - if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) + /* COPY or NEW space */ + if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) { + kfree(task); return PTR_ERR(-ENOMEM); + } link_init(&task->utcb_head->list); } diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index d2f0c3e..61b0f53 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -17,76 +17,70 @@ /* Extern declarations */ extern void setup_new_thread(void); extern unsigned long lib_stack_size; +extern unsigned long lib_utcb_range_size; /* Static variable definitions */ struct l4_mutex lib_mutex; /* Function definitions */ int l4_thread_create(struct task_ids *ids, unsigned int flags, - void *(*func)(void *), void *arg) + int (*func)(void *), void *arg) { struct exregs_data exregs; unsigned long utcb_addr; - struct l4t_tcb *parent, *child; - int err; + struct tcb *parent, *child; unsigned long stack_top_addr, stack_bot_addr; + int err = 0; /* A few controls before granting access to thread creation */ - // FIXME: check if utcb region is setup - if (!IS_STACK_SETUP()) { + if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { printf("libl4thread: Stack and/or utcb have not been " - "set up.\n"); + "set up.\n"); return -EPERM; } - // FIXME: Check if there is enough stack space - - // FIXME: Check if there is enough utcb space - - if (!(TC_SHARE_SPACE & flags)) { - printf("libl4thread: Only allows shared space thread " - "creation.\n"); - - return -EINVAL; - } - /* Before doing any operation get the global mutex. */ l4_mutex_lock(&lib_mutex); /* Get parent's ids and find the tcb belonging to it. */ l4_getid(ids); - if (!(parent = l4t_find_task(ids->tid))) - return-ESRCH; + if (!(parent = find_task(ids->tid))) { + err = -ESRCH; + goto out_err1; + } /* Allocate tcb for the child. */ - if (!(child = l4t_tcb_alloc_init(parent, flags))) { + if (!(child = tcb_alloc_init(parent, flags))) { + // FIXME: What happens to utcb_head printf("libl4thread: No heap space left.\n"); - return -ENOMEM; + err = -ENOMEM; + goto out_err1; } /* Get a utcb addr. */ 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; + printf("libl4thread: No utcb space left.\n"); + err = -ENOMEM; + goto out_err2; } + /* Get a stack space and calculate the bottom addr of the stack. */ + stack_top_addr = (unsigned long)get_stack_space(); + if (!stack_top_addr) { + printf("libl4thread: No stack space left.\n"); + err = -ENOMEM; + goto out_err3; + } + stack_bot_addr = stack_top_addr + lib_stack_size; + child->stack_addr = stack_top_addr; + /* 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; + "failed with (%d).\n", err); + goto out_err4; } - /* Get a stack space and calculate the bottom addr of the stack. */ - stack_top_addr = (unsigned long)get_stack_space(1, lib_stack_size); - stack_bot_addr = stack_top_addr + lib_stack_size; - child->stack_addr = stack_top_addr; - /* Setup new thread pc, sp, utcb */ memset(&exregs, 0, sizeof(exregs)); exregs_set_stack(&exregs, align((stack_bot_addr - 1), 8)); @@ -95,9 +89,8 @@ int l4_thread_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; + "(%d).\n", err); + goto out_err5; } /* First word of new stack is arg */ @@ -109,25 +102,42 @@ int l4_thread_create(struct task_ids *ids, unsigned int flags, /* Add child to the global task list */ child->tid = ids->tid; - l4t_global_add_task(child); + global_add_task(child); /* Start the new thread */ if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { - // FIXME: Check if there is any memory leak printf("libl4thread: l4_thread_control(THREAD_RUN) " - "failed with (%d).\n", err); - return err; + "failed with (%d).\n", err); + goto out_err6; } /* Release the global mutex. */ l4_mutex_unlock(&lib_mutex); return 0; + + /* Error handling. */ +out_err6: + global_remove_task(child); +out_err5: + l4_thread_control(THREAD_DESTROY, ids); +out_err4: + delete_stack_space((void *)child->stack_addr); +out_err3: + delete_utcb_addr(child); +out_err2: + if ((flags & TC_COPY_SPACE) || (flags & TC_NEW_SPACE)) + kfree(child->utcb_head); + kfree(child); +out_err1: + l4_mutex_unlock(&lib_mutex); + + return err; } -void l4_thread_exit(void *retval) +void l4_thread_exit(int retval) { - struct l4t_tcb *task; + struct tcb *task; struct task_ids ids; /* Before doing any operation get the global mutex. */ @@ -136,26 +146,28 @@ void l4_thread_exit(void *retval) /* Find the task. */ l4_getid(&ids); /* Cant find the thread means it wasnt added to the list. */ - if (!(task = l4t_find_task(ids.tid))) + if (!(task = find_task(ids.tid))) + BUG(); + + /* Remove child from the global task list. */ + global_remove_task(task); + + /* Delete the stack space. */ + if (delete_stack_space((void *)task->stack_addr) < 0) BUG(); /* Delete the utcb address. */ delete_utcb_addr(task); - /* Delete the stack region. */ - delete_stack_space((void *)task->stack_addr, 1, lib_stack_size); - - /* Remove child from the global task list. */ - l4t_global_remove_task(task); - // FIXME: We assume that main thread never leaves the scene + // FIXME: What happens to task->utcb_head? kfree(task); /* Release the global mutex. */ l4_mutex_unlock(&lib_mutex); /* Relinquish the control. */ - l4_exit(*(unsigned int *)retval); + l4_exit(retval); /* Should never reach here. */ BUG(); @@ -163,27 +175,29 @@ void l4_thread_exit(void *retval) int l4_thread_kill(struct task_ids *ids) { - struct l4t_tcb *task; + struct tcb *task; /* Before doing any operation get the global mutex. */ l4_mutex_lock(&lib_mutex); /* Find the task to be killed. */ - if (!(task = l4t_find_task(ids->tid))) { + if (!(task = find_task(ids->tid))) { l4_mutex_unlock(&lib_mutex); return -ESRCH; } + /* Remove child from the global task list. */ + global_remove_task(task); + + /* Delete the stack space. */ + if (delete_stack_space((void *)task->stack_addr) < 0) + BUG(); + /* Delete the utcb address. */ delete_utcb_addr(task); - /* Delete the stack region. */ - delete_stack_space((void *)task->stack_addr, 1, lib_stack_size); - - /* Remove child from the global task list. */ - l4t_global_remove_task(task); - // FIXME: We assume that main thread never leaves the scene + // FIXME: What happens to task->utcb_head? kfree(task); /* Release the global mutex. */ diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c index 4356be9..5ad511a 100644 --- a/conts/libl4thread/src/utcb-common.c +++ b/conts/libl4thread/src/utcb-common.c @@ -18,7 +18,7 @@ int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) /* Initialise the global utcb virtual address pool */ if ((err = address_pool_init(&utcb_region_pool, utcb_start, utcb_end, - UTCB_SIZE) < 0)) { + PAGE_SIZE) < 0)) { printf("UTCB address pool initialisation failed.\n"); return err; } @@ -72,7 +72,11 @@ struct utcb_desc *utcb_new_desc(void) /* Obtain a new and unique utcb base */ /* FIXME: Use variable size than a page */ - d->utcb_base = (unsigned long)utcb_new_address(1); + if (!(d->utcb_base = (unsigned long)utcb_new_address(1))) { + kfree(d->slots); + kfree(d); + return 0; + } return d; } diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 8415ff8..5bed78c 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -1,5 +1,5 @@ /* - * UTCB handling helper routines + * UTCB handling helper routines. * * Copyright (C) 2009 B Labs Ltd. */ @@ -13,10 +13,13 @@ #include /* Extern declarations */ -extern struct l4t_global_list l4t_global_tasks; +extern struct global_list global_tasks; + +/* Global variables */ +unsigned long lib_utcb_range_size; /* Function definitions */ -unsigned long get_utcb_addr(struct l4t_tcb *task) +unsigned long get_utcb_addr(struct tcb *task) { struct utcb_desc *udesc; unsigned long slot; @@ -30,7 +33,8 @@ unsigned long get_utcb_addr(struct l4t_tcb *task) goto found; /* Allocate a new utcb memory region and return its base. */ - udesc = utcb_new_desc(); + if (!(udesc = utcb_new_desc())) + return 0; slot = utcb_new_slot(udesc); list_insert(&udesc->list, &task->utcb_head->list); found: @@ -39,7 +43,7 @@ found: return slot; } -int delete_utcb_addr(struct l4t_tcb *task) +int delete_utcb_addr(struct tcb *task) { struct utcb_desc *udesc; @@ -68,29 +72,31 @@ static int set_utcb_addr(void) { struct exregs_data exregs; struct task_ids ids; - struct l4t_tcb *task; + struct tcb *task; struct utcb_desc *udesc; int err; /* Create a task. */ - if (IS_ERR(task = l4t_tcb_alloc_init(0, 0))) + if (IS_ERR(task = 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++; + list_insert_tail(&task->list, &global_tasks.list); + global_tasks.total++; - udesc = utcb_new_desc(); + if (!(udesc = utcb_new_desc())) + return -ENOMEM; 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)task->utcb_addr); + exregs_set_utcb(&exregs, task->utcb_addr); l4_getid(&ids); + task->tid = ids.tid; if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " - "(%d).\n", err); + "(%d).\n", err); return err; } @@ -102,21 +108,20 @@ int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) int err; /* Ensure that arguments are valid. */ - // FIXME: Check if set_utcb_params is called - /*if (IS_UTCB_SETUP()) {*/ - /*printf("libl4thread: You have already called: %s.\n",*/ - /*__FUNCTION__);*/ - /*return -EPERM;*/ - /*}*/ + 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"); return -EINVAL; } - /* Check if the start address is aligned on UTCB_SIZE. */ - if (utcb_start & !UTCB_SIZE) { + /* Check if the start address is aligned on PAGE_SIZE. */ + if (utcb_start & PAGE_MASK) { printf("libl4thread: Utcb start address must be aligned " - "on UTCB_SIZE(0x%x).\n", UTCB_SIZE); + "on PAGE_SIZE(0x%x).\n", PAGE_SIZE); return -EINVAL; } /* The range must be a valid one. */ @@ -138,11 +143,18 @@ int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) /* Arguments passed the validity tests. */ /* Init utcb virtual address pool. */ - utcb_pool_init(utcb_start, utcb_end); + if (utcb_pool_init(utcb_start, utcb_end) < 0) + BUG(); - /* The very first thread's utcb address is assigned. */ + /* + * The very first thread's utcb address is assigned. + * It should not return an error value. + */ if ((err = set_utcb_addr()) < 0) - return err; + BUG(); + + /* Initialize internal variables. */ + lib_utcb_range_size = utcb_end - utcb_start; return 0; }