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; }