From 52587141f40523702d4ab4bae6644a862eb59688 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 5 Nov 2009 15:20:54 +0200 Subject: [PATCH 1/3] The second step in creating a thread library. UTCB support has beed added. It has the same drawback as in the stack support: the area in question has to be already mapped-in. There are also some minor fixes for the stack support and the utcb common helper routines. --- conts/libl4thread/include/l4thread/addr.h | 5 +- conts/libl4thread/include/l4thread/thread.h | 14 +- .../include/l4thread/utcb-common.h | 25 +++ conts/libl4thread/include/l4thread/utcb.h | 22 +-- conts/libl4thread/src/addr.c | 6 +- conts/libl4thread/src/thread.c | 32 +++- conts/libl4thread/src/utcb-common.c | 89 +++++++++++ conts/libl4thread/src/utcb.c | 148 ++++++++++-------- 8 files changed, 249 insertions(+), 92 deletions(-) create mode 100644 conts/libl4thread/include/l4thread/utcb-common.h create mode 100644 conts/libl4thread/src/utcb-common.c diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h index 5bbc69d..e7b4519 100644 --- a/conts/libl4thread/include/l4thread/addr.h +++ b/conts/libl4thread/include/l4thread/addr.h @@ -18,8 +18,9 @@ struct address_pool { int address_pool_init_with_idpool(struct address_pool *pool, struct id_pool *idpool, unsigned long start, unsigned long end); -int address_pool_init(struct address_pool *pool, unsigned long start, - unsigned long end); +int address_pool_init(struct address_pool *pool, + unsigned long start, unsigned long end, + int size); void *address_new(struct address_pool *pool, int npages); int address_del(struct address_pool *, void *addr, int npages); diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 658d17b..ce41f16 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -6,13 +6,21 @@ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ -#define STACK_TOP_ADDR(stack) ((unsigned long)(stack)) -#define STACK_BOTTOM_ADDR(stack) \ - ((unsigned long)((stack) + (sizeof(stack)))) +#define START_ADDR(addr) ((unsigned long)(addr)) +#define END_ADDR(addr) ((unsigned long)((addr) + (sizeof(addr)))) + +#define STACK_TOP_ADDR(stack) (START_ADDR(stack)) +#define STACK_BOTTOM_ADDR(stack) (END_ADDR(stack)) + +#define UTCB_START_ADDR(utcb) (START_ADDR(utcb)) +#define UTCB_END_ADDR(utcb) (END_ADDR(utcb)) int set_stack_params(unsigned long stack_top_addr, unsigned long stack_bottom_addr, unsigned long stack_size); +int set_utcb_params(unsigned long utcb_start_addr, + unsigned long utcb_end_addr); + int thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); diff --git a/conts/libl4thread/include/l4thread/utcb-common.h b/conts/libl4thread/include/l4thread/utcb-common.h new file mode 100644 index 0000000..e5f5fef --- /dev/null +++ b/conts/libl4thread/include/l4thread/utcb-common.h @@ -0,0 +1,25 @@ +/* + * UTCB handling common helper routines + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __UTCB_COMMON_H__ +#define __UTCB_COMMON_H__ + +#include + +struct utcb_desc { + struct link list; + unsigned long utcb_base; + struct id_pool *slots; +}; + +int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end); + +unsigned long utcb_new_slot(struct utcb_desc *desc); +int utcb_delete_slot(struct utcb_desc *desc, unsigned long address); + +struct utcb_desc *utcb_new_desc(void); +int utcb_delete_desc(struct utcb_desc *desc); + +#endif /* __UTCB_COMMON_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h index 464bd45..32049e5 100644 --- a/conts/libl4thread/include/l4thread/utcb.h +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -3,23 +3,13 @@ * * Copyright (C) 2009 B Labs Ltd. */ -#ifndef __UTCB_H__ -#define __UTCB_H__ +#ifndef __LIB_UTCB_H__ +#define __LIB_UTCB_H__ -#include +#define IS_UTCB_SETUP() (udesc_ptr) -struct utcb_desc { - struct link list; - unsigned long utcb_base; - struct id_pool *slots; -}; +struct utcb_desc *udesc_ptr; -int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end); +unsigned long get_utcb_addr(void); -unsigned long utcb_new_slot(struct utcb_desc *desc); -int utcb_delete_slot(struct utcb_desc *desc, unsigned long address); - -struct utcb_desc *utcb_new_desc(void); -int utcb_delete_desc(struct utcb_desc *desc); - -#endif /* __UTCB_H__ */ +#endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/addr.c b/conts/libl4thread/src/addr.c index 10206bd..90c67dd 100644 --- a/conts/libl4thread/src/addr.c +++ b/conts/libl4thread/src/addr.c @@ -22,9 +22,11 @@ int address_pool_init_with_idpool(struct address_pool *pool, return 0; } -int address_pool_init(struct address_pool *pool, unsigned long start, unsigned long end) +int address_pool_init(struct address_pool *pool, + unsigned long start, unsigned long end, + int size) { - if ((pool->idpool = id_pool_new_init(__pfn(end - start))) < 0) + if ((pool->idpool = id_pool_new_init((end - start) / size)) < 0) return (int)pool->idpool; pool->start = start; pool->end = end; diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index e11572c..cfaaaca 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -8,6 +8,7 @@ #include #include #include +#include /* Symbolic constants and macros */ #define STACK_PTR(addr) align((addr - 1), 8) @@ -26,11 +27,18 @@ int set_stack_params(unsigned long stack_top_addr, unsigned long stack_bottom_addr, unsigned long stack_size) { + /* Ensure that arguments are valid. */ if (IS_STACK_SETUP()) { printf("libl4thread: You have already called: %s. Simply, " "this will have no effect!\n", __FUNCTION__); return -EPERM; } + if (!stack_top_addr || !stack_bottom_addr) { + printf("libl4thread: stack address range cannot contain " + "0x00000000 as a start and/or end address(es)!\n"); + return -EINVAL; + } + // FIXME: Aligning should be taken into account. /* * Stack grows downward so the top of the stack will have * the lowest numbered address. @@ -44,12 +52,15 @@ int set_stack_params(unsigned long stack_top_addr, printf("libl4thread: Stack size cannot be zero!\n"); return -EINVAL; } - /* stack_size at least must be equal to the difference */ + /* stack_size at least must be equal to the difference. */ if ((stack_bottom_addr - stack_top_addr) < stack_size) { printf("libl4thread: the given range size is lesser than " - "the stack size!\n"); + "the stack size(0x%x)!\n", stack_size); return -EINVAL; } + /* Arguments passed the validity tests. */ + + /* Initialize internal variables */ lib_stack_bot_addr = stack_bottom_addr; lib_stack_top_addr = stack_top_addr; lib_stack_size = stack_size; @@ -61,13 +72,15 @@ int thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg) { struct exregs_data exregs; + unsigned long utcb_addr; int err; /* A few controls before granting access to thread creation */ - if (!IS_STACK_SETUP()) { - printf("libl4thread: Stack has not been set up. Before " - "calling thread_create, set_stack_params " - "has to be called!\n"); + if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { + printf("libl4thread: Stack and/or utcb have not been set up. " + "Before calling thread_create, set_stack_params " + "and/or set_utcb_params have to be called with valid " + "arguments!\n"); return -EPERM; } @@ -85,6 +98,12 @@ int thread_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"); + return -ENOMEM; + } + /* Get parent's ids */ l4_getid(ids); @@ -99,6 +118,7 @@ int thread_create(struct task_ids *ids, unsigned int flags, memset(&exregs, 0, sizeof(exregs)); exregs_set_stack(&exregs, STACK_PTR(lib_stack_bot_addr)); exregs_set_pc(&exregs, (unsigned long)setup_new_thread); + exregs_set_utcb(&exregs, (unsigned long)utcb_addr); if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c new file mode 100644 index 0000000..38df843 --- /dev/null +++ b/conts/libl4thread/src/utcb-common.c @@ -0,0 +1,89 @@ +/* + * UTCB management in Codezero + * + * Copyright © 2009 B Labs Ltd + */ +#include +#include +#include +#include + +/* Globally disjoint utcb virtual region pool */ +static struct address_pool utcb_region_pool; + +int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) +{ + int err; + + /* Initialise the global utcb virtual address pool */ + if ((err = address_pool_init(&utcb_region_pool, + utcb_start, utcb_end, + UTCB_SIZE) < 0)) { + printf("UTCB address pool initialisation failed.\n"); + return err; + } + + return 0; +} + +static inline void *utcb_new_address(int npages) +{ + return address_new(&utcb_region_pool, npages); +} + +static inline int utcb_delete_address(void *utcb_address, int npages) +{ + return address_del(&utcb_region_pool, utcb_address, npages); +} + +/* Return an empty utcb slot in this descriptor */ +unsigned long utcb_new_slot(struct utcb_desc *desc) +{ + int slot; + + if ((slot = id_new(desc->slots)) < 0) + return 0; + else + return desc->utcb_base + (unsigned long)slot * UTCB_SIZE; +} + +int utcb_delete_slot(struct utcb_desc *desc, unsigned long address) +{ + BUG_ON(id_del(desc->slots, (address - desc->utcb_base) + / UTCB_SIZE) < 0); + return 0; +} + +struct utcb_desc *utcb_new_desc(void) +{ + struct utcb_desc *d; + + /* Allocate a new descriptor */ + if (!(d = kzalloc(sizeof(*d)))) + return 0; + + link_init(&d->list); + + /* We currently assume UTCB is smaller than PAGE_SIZE */ + BUG_ON(UTCB_SIZE > PAGE_SIZE); + + /* Initialise utcb slots */ + d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE); + + /* Obtain a new and unique utcb base */ + /* FIXME: Use variable size than a page */ + d->utcb_base = (unsigned long)utcb_new_address(1); + + return d; +} + +int utcb_delete_desc(struct utcb_desc *desc) +{ + /* Return descriptor address */ + utcb_delete_address((void *)desc->utcb_base, 1); + + /* Free the descriptor */ + kfree(desc); + + return 0; +} diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 9dcc187..7298bf0 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -1,88 +1,110 @@ /* - * UTCB management in Codezero + * UTCB handling helper routines * - * Copyright © 2009 B Labs Ltd + * Copyright (C) 2009 B Labs Ltd. */ #include -#include -#include +#include +#include +#include #include +#include +#include -/* Globally disjoint utcb virtual region pool */ -static struct address_pool utcb_region_pool; +/* Static variable definitions */ +static unsigned long utcb_end_max_addr; -int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) +/* Function definitions */ +unsigned long get_utcb_addr(void) { + unsigned long utcb_addr; + + if (!(utcb_addr = utcb_new_slot(udesc_ptr))) { + udesc_ptr = utcb_new_desc(); + utcb_addr = utcb_new_slot(udesc_ptr); + } + + if (utcb_addr >= utcb_end_max_addr) + return 0; + + return utcb_addr; +} + +static int set_utcb_addr(void) +{ + struct exregs_data exregs; + unsigned long utcb_addr; + struct task_ids ids; int err; - /* Initialise the global utcb virtual address pool */ - if ((err = address_pool_init(&utcb_region_pool, - utcb_start, utcb_end) < 0)) { - printf("UTCB address pool initialisation failed.\n"); + l4_getid(&ids); + // FIXME: its tid must be 0. + udesc_ptr = utcb_new_desc(); + utcb_addr = get_utcb_addr(); + + memset(&exregs, 0, sizeof(exregs)); + exregs_set_utcb(&exregs, (unsigned long)utcb_addr); + + if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { + printf("libl4thread: l4_exchange_registers failed with " + "(%d)!\n", err); return err; } return 0; } -static inline void *utcb_new_address(int npages) +int set_utcb_params(unsigned long utcb_start_addr, + unsigned long utcb_end_addr) { - return address_new(&utcb_region_pool, npages); -} + int err; -static inline int utcb_delete_address(void *utcb_address, int npages) -{ - return address_del(&utcb_region_pool, utcb_address, npages); -} + /* Ensure that arguments are valid. */ + if (IS_UTCB_SETUP()) { + printf("libl4thread: You have already called: %s. Simply, " + "this will have no effect!\n", __FUNCTION__); + return -EPERM; + } + if (!utcb_start_addr || !utcb_end_addr) { + printf("libl4thread: utcb address range cannot contain " + "0x00000000 as a start and/or end address(es)!\n"); + return -EINVAL; + } + /* Check if the start address is aligned on UTCB_SIZE. */ + if (utcb_start_addr & !UTCB_SIZE) { + printf("libl4thread: utcb start address must be aligned " + "on UTCB_SIZE(0x%x)\n", UTCB_SIZE); + return -EINVAL; + } + /* The range must be a valid one. */ + if (utcb_start_addr >= utcb_end_addr) { + printf("libl4thread: utcb end address must be bigger " + "than utcb start address!\n"); + return -EINVAL; + } + /* + * This check guarantees two things: + * 1. The range must be multiple of UTCB_SIZE, at least one item. + * 2. utcb_end_addr is aligned on UTCB_SIZE + */ + if ((utcb_end_addr - utcb_start_addr) % UTCB_SIZE) { + printf("libl4thread: the given range size must be multiple " + "of the utcb size(%d)!\n", UTCB_SIZE); + return -EINVAL; + } + /* Arguments passed the validity tests. */ -/* Return an empty utcb slot in this descriptor */ -unsigned long utcb_new_slot(struct utcb_desc *desc) -{ - int slot; + /* Init utcb virtual address pool */ + utcb_pool_init(utcb_start_addr, utcb_end_addr); - if ((slot = id_new(desc->slots)) < 0) - return 0; - else - return desc->utcb_base + (unsigned long)slot * UTCB_SIZE; -} + utcb_end_max_addr = utcb_end_addr; + + /* The very first thread's utcb address is assigned. */ + if ((err = set_utcb_addr()) < 0) + return err; -int utcb_delete_slot(struct utcb_desc *desc, unsigned long address) -{ - BUG_ON(id_del(desc->slots, (address - desc->utcb_base) - / UTCB_SIZE) < 0); return 0; } -struct utcb_desc *utcb_new_desc(void) -{ - struct utcb_desc *d; +/*void destroy_utcb(void) {}*/ - /* Allocate a new descriptor */ - if (!(d = kzalloc(sizeof(*d)))) - return 0; - - link_init(&d->list); - - /* We currently assume UTCB is smaller than PAGE_SIZE */ - BUG_ON(UTCB_SIZE > PAGE_SIZE); - - /* Initialise utcb slots */ - d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE); - - /* Obtain a new and unique utcb base */ - /* FIXME: Use variable size than a page */ - d->utcb_base = (unsigned long)utcb_new_address(1); - - return d; -} - -int utcb_delete_desc(struct utcb_desc *desc) -{ - /* Return descriptor address */ - utcb_delete_address((void *)desc->utcb_base, 1); - - /* Free the descriptor */ - kfree(desc); - - return 0; -} From 8f55e72f00573797c8843d07a1b8021932f73f3b Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 5 Nov 2009 22:09:37 +0200 Subject: [PATCH 2/3] Lots of cosmetic changes to the thread library. --- conts/libl4thread/include/l4thread/thread.h | 18 ++---- conts/libl4thread/src/thread.c | 62 ++++++++++----------- conts/libl4thread/src/utcb.c | 43 +++++++------- 3 files changed, 54 insertions(+), 69 deletions(-) diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index ce41f16..c1ce0a9 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -6,22 +6,12 @@ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ -#define START_ADDR(addr) ((unsigned long)(addr)) -#define END_ADDR(addr) ((unsigned long)((addr) + (sizeof(addr)))) - -#define STACK_TOP_ADDR(stack) (START_ADDR(stack)) -#define STACK_BOTTOM_ADDR(stack) (END_ADDR(stack)) - -#define UTCB_START_ADDR(utcb) (START_ADDR(utcb)) -#define UTCB_END_ADDR(utcb) (END_ADDR(utcb)) - -int set_stack_params(unsigned long stack_top_addr, - unsigned long stack_bottom_addr, +int set_stack_params(unsigned long stack_top, + unsigned long stack_bottom, unsigned long stack_size); -int set_utcb_params(unsigned long utcb_start_addr, - unsigned long utcb_end_addr); +int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); -int thread_create(struct task_ids *ids, unsigned int flags, +int l4thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index cfaaaca..19b856e 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -11,7 +11,6 @@ #include /* Symbolic constants and macros */ -#define STACK_PTR(addr) align((addr - 1), 8) #define IS_STACK_SETUP() (lib_stack_size) /* Extern declarations */ @@ -23,19 +22,19 @@ static unsigned long lib_stack_bot_addr; static unsigned long lib_stack_size; /* Function definitions */ -int set_stack_params(unsigned long stack_top_addr, - unsigned long stack_bottom_addr, +int set_stack_params(unsigned long stack_top, + unsigned long stack_bottom, unsigned long stack_size) { /* Ensure that arguments are valid. */ if (IS_STACK_SETUP()) { - printf("libl4thread: You have already called: %s. Simply, " - "this will have no effect!\n", __FUNCTION__); + printf("libl4thread: You have already called: %s.\n", + __FUNCTION__); return -EPERM; } - if (!stack_top_addr || !stack_bottom_addr) { - printf("libl4thread: stack address range cannot contain " - "0x00000000 as a start and/or end address(es)!\n"); + if (!stack_top || !stack_bottom) { + printf("libl4thread: Stack address range cannot contain " + "0x0 as a start and/or end address(es).\n"); return -EINVAL; } // FIXME: Aligning should be taken into account. @@ -43,32 +42,32 @@ int set_stack_params(unsigned long stack_top_addr, * Stack grows downward so the top of the stack will have * the lowest numbered address. */ - if (stack_top_addr >= stack_bottom_addr) { + if (stack_top >= stack_bottom) { printf("libl4thread: Stack bottom address must be bigger " - "than stack top address!\n"); + "than stack top address.\n"); return -EINVAL; } if (!stack_size) { - printf("libl4thread: Stack size cannot be zero!\n"); + printf("libl4thread: Stack size cannot be zero.\n"); return -EINVAL; } /* stack_size at least must be equal to the difference. */ - if ((stack_bottom_addr - stack_top_addr) < stack_size) { - printf("libl4thread: the given range size is lesser than " - "the stack size(0x%x)!\n", stack_size); + if ((stack_bottom - stack_top) < stack_size) { + printf("libl4thread: The given range size is lesser than " + "the stack size(0x%x).\n", stack_size); return -EINVAL; } /* Arguments passed the validity tests. */ /* Initialize internal variables */ - lib_stack_bot_addr = stack_bottom_addr; - lib_stack_top_addr = stack_top_addr; + lib_stack_bot_addr = stack_bottom; + lib_stack_top_addr = stack_top; lib_stack_size = stack_size; return 0; } -int thread_create(struct task_ids *ids, unsigned int flags, +int l4thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg) { struct exregs_data exregs; @@ -77,30 +76,27 @@ int thread_create(struct task_ids *ids, unsigned int flags, /* A few controls before granting access to thread creation */ if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { - printf("libl4thread: Stack and/or utcb have not been set up. " - "Before calling thread_create, set_stack_params " - "and/or set_utcb_params have to be called with valid " - "arguments!\n"); + printf("libl4thread: Stack and/or utcb have not been " + "set up.\n"); return -EPERM; } /* Is there enough stack space for the new thread? */ if (lib_stack_top_addr >= lib_stack_bot_addr) { - printf("libl4thread: no stack space left!\n"); + printf("libl4thread: No stack space left.\n"); return -ENOMEM; } if (!(TC_SHARE_SPACE & flags)) { - printf("libl4thread: SAME address space is supported, which " - "means the only way to create a thread is with " - "TC_SHARE_SPACE flag. Other means of creating a " - "thread have not been supported yet!\n"); + printf("libl4thread: Only allows shared space thread " + "creation.\n"); + return -EINVAL; } /* Get a utcb addr for this thread */ if (!(utcb_addr = get_utcb_addr())) { - printf("libl4thread: No utcb address left!\n"); + printf("libl4thread: No utcb address left.\n"); return -ENOMEM; } @@ -110,27 +106,27 @@ int thread_create(struct task_ids *ids, unsigned int flags, /* Create thread */ if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_CREATE) " - "failed with (%d)!\n", err); + "failed with (%d).\n", err); return err; } /* Setup new thread pc, sp, utcb */ memset(&exregs, 0, sizeof(exregs)); - exregs_set_stack(&exregs, STACK_PTR(lib_stack_bot_addr)); + exregs_set_stack(&exregs, align((lib_stack_bot_addr - 1), 8)); exregs_set_pc(&exregs, (unsigned long)setup_new_thread); exregs_set_utcb(&exregs, (unsigned long)utcb_addr); if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " - "(%d)!\n", err); + "(%d).\n", err); return err; } /* First word of new stack is arg */ - ((unsigned long *)STACK_PTR(lib_stack_bot_addr))[0] = + ((unsigned long *)align((lib_stack_bot_addr - 1), 8))[0] = (unsigned long)arg; /* Second word of new stack is function address */ - ((unsigned long *)STACK_PTR(lib_stack_bot_addr))[-1] = + ((unsigned long *)align((lib_stack_bot_addr - 1), 8))[-1] = (unsigned long)func; /* Update the stack address */ lib_stack_bot_addr -= lib_stack_size; @@ -138,7 +134,7 @@ int thread_create(struct task_ids *ids, unsigned int flags, /* Start the new thread */ if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_RUN) " - "failed with (%d)!\n", err); + "failed with (%d).\n", err); return err; } diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 7298bf0..049bcbe 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -12,7 +12,7 @@ #include /* Static variable definitions */ -static unsigned long utcb_end_max_addr; +static unsigned long lib_utcb_end_addr; /* Function definitions */ unsigned long get_utcb_addr(void) @@ -24,7 +24,7 @@ unsigned long get_utcb_addr(void) utcb_addr = utcb_new_slot(udesc_ptr); } - if (utcb_addr >= utcb_end_max_addr) + if (utcb_addr >= lib_utcb_end_addr) return 0; return utcb_addr; @@ -47,57 +47,56 @@ static int set_utcb_addr(void) if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " - "(%d)!\n", err); + "(%d).\n", err); return err; } return 0; } -int set_utcb_params(unsigned long utcb_start_addr, - unsigned long utcb_end_addr) +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. Simply, " - "this will have no effect!\n", __FUNCTION__); + printf("libl4thread: You have already called: %s.\n", + __FUNCTION__); return -EPERM; } - if (!utcb_start_addr || !utcb_end_addr) { - printf("libl4thread: utcb address range cannot contain " - "0x00000000 as a start and/or end address(es)!\n"); + 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_addr & !UTCB_SIZE) { - printf("libl4thread: utcb start address must be aligned " - "on UTCB_SIZE(0x%x)\n", UTCB_SIZE); + if (utcb_start & !UTCB_SIZE) { + printf("libl4thread: Utcb start address must be aligned " + "on UTCB_SIZE(0x%x).\n", UTCB_SIZE); return -EINVAL; } /* The range must be a valid one. */ - if (utcb_start_addr >= utcb_end_addr) { - printf("libl4thread: utcb end address must be bigger " - "than utcb start address!\n"); + if (utcb_start >= utcb_end) { + printf("libl4thread: Utcb end address must be bigger " + "than utcb start address.\n"); return -EINVAL; } /* * This check guarantees two things: * 1. The range must be multiple of UTCB_SIZE, at least one item. - * 2. utcb_end_addr is aligned on UTCB_SIZE + * 2. utcb_end is aligned on UTCB_SIZE */ - if ((utcb_end_addr - utcb_start_addr) % UTCB_SIZE) { - printf("libl4thread: the given range size must be multiple " - "of the utcb size(%d)!\n", UTCB_SIZE); + if ((utcb_end - utcb_start) % UTCB_SIZE) { + printf("libl4thread: The given range size must be multiple " + "of the utcb size(%d).\n", UTCB_SIZE); return -EINVAL; } /* Arguments passed the validity tests. */ /* Init utcb virtual address pool */ - utcb_pool_init(utcb_start_addr, utcb_end_addr); + utcb_pool_init(utcb_start, utcb_end); - utcb_end_max_addr = utcb_end_addr; + lib_utcb_end_addr = utcb_end; /* The very first thread's utcb address is assigned. */ if ((err = set_utcb_addr()) < 0) From a23b7fcbc2f4f986dcf2dfffc06ccde0710ba20e Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 10 Nov 2009 14:46:54 +0200 Subject: [PATCH 3/3] 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) {}*/ -