From dcd9e0659f57937ce7c72a76af6047d5de6596ab Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Mon, 12 Sep 2016 20:15:36 +0300 Subject: [PATCH 1/3] lkl tools: tests: initialize test buffer This avoids garbage being printed for tests that don't use the test print buffer. Signed-off-by: Octavian Purdila --- tools/lkl/tests/test.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lkl/tests/test.h b/tools/lkl/tests/test.h index f52c7382158bc9..fabcbd121b1e74 100644 --- a/tools/lkl/tests/test.h +++ b/tools/lkl/tests/test.h @@ -5,7 +5,7 @@ static int g_test_pass = 0; #define TEST(name, ...) \ { \ - char str[MAX_MSG_LEN]; \ + char str[MAX_MSG_LEN] = { 0, }; \ int (*fn)(char *str, int len, ...); \ int ret; \ \ From fe5d96bf495da76ad0664f93f908cd591592f926 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Thu, 15 Sep 2016 23:52:24 +0300 Subject: [PATCH 2/3] lkl tools: tests: move basic tests at the beginning This patch allows us to verify basic host operations before starting the kernel. It also fixes a couple of coding style issues. Signed-off-by: Octavian Purdila --- tools/lkl/tests/boot.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c index 2492c313ddd750..8b2376415d748d 100644 --- a/tools/lkl/tests/boot.c +++ b/tools/lkl/tests/boot.c @@ -673,9 +673,10 @@ static int test_lo_ifup(char *str, int len) static int test_mutex(char *str, int len) { long ret = TEST_SUCCESS; - /* Can't do much to verify that this works, so we'll just let - * Valgrind warn us on CI if we've made bad memory - * accesses. */ + /* + * Can't do much to verify that this works, so we'll just let Valgrind + * warn us on CI if we've made bad memory accesses. + */ struct lkl_mutex *mutex = lkl_host_ops.mutex_alloc(); lkl_host_ops.mutex_lock(mutex); @@ -690,9 +691,10 @@ static int test_mutex(char *str, int len) static int test_semaphore(char *str, int len) { long ret = TEST_SUCCESS; - /* Can't do much to verify that this works, so we'll just let - * Valgrind warn us on CI if we've made bad memory - * accesses. */ + /* + * Can't do much to verify that this works, so we'll just let Valgrind + * warn us on CI if we've made bad memory accesses. + */ struct lkl_sem *sem = lkl_host_ops.sem_alloc(1); lkl_host_ops.sem_down(sem); @@ -893,6 +895,10 @@ int main(int argc, char **argv) lkl_host_ops.print = printk; + TEST(mutex); + TEST(semaphore); + TEST(join); + if (cla.disk_filename) TEST(disk_add); #ifndef __MINGW32__ @@ -934,11 +940,8 @@ int main(int argc, char **argv) TEST(umount_dev); } TEST(lo_ifup); - TEST(mutex); - TEST(semaphore); TEST(gettid); TEST(syscall_thread); - TEST(join); /* * Wine has an issue where the FlsCallback is not called when the thread * terminates which makes testing the automatic syscall threads cleanup From c9a19fc36a0393f2fc370217ed1c173390c2cce6 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 16 Sep 2016 00:39:40 +0300 Subject: [PATCH 3/3] lkl: simplfy thread exit Instead of using the thread_exit_info structure on stack use thread_join to wait wait the thread to exit before freeing the thread_info memory. Signed-off-by: Octavian Purdila --- arch/lkl/include/asm/thread_info.h | 11 ++--- arch/lkl/kernel/threads.c | 76 ++++++++++++------------------ 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/arch/lkl/include/asm/thread_info.h b/arch/lkl/include/asm/thread_info.h index 3b9d047181b6e9..0f1ec2b8add739 100644 --- a/arch/lkl/include/asm/thread_info.h +++ b/arch/lkl/include/asm/thread_info.h @@ -6,23 +6,20 @@ #ifndef __ASSEMBLY__ #include #include +#include typedef struct { unsigned long seg; } mm_segment_t; -struct thread_exit_info { - bool dead; - void *sched_sem; -}; - struct thread_info { struct task_struct *task; unsigned long flags; int preempt_count; mm_segment_t addr_limit; - void *sched_sem; - struct thread_exit_info *exit_info; + struct lkl_sem *sched_sem; + bool dead; + lkl_thread_t tid; struct task_struct *prev_sched; unsigned long stackend; }; diff --git a/arch/lkl/kernel/threads.c b/arch/lkl/kernel/threads.c index 3287daa389aca5..f8b673e838c0ae 100644 --- a/arch/lkl/kernel/threads.c +++ b/arch/lkl/kernel/threads.c @@ -5,6 +5,19 @@ static volatile int threads_counter; +static int init_ti(struct thread_info *ti) +{ + ti->sched_sem = lkl_ops->sem_alloc(0); + if (!ti->sched_sem) + return -ENOMEM; + + ti->dead = false; + ti->prev_sched = NULL; + ti->tid = 0; + + return 0; +} + unsigned long *alloc_thread_stack_node(struct task_struct *task, int node) { struct thread_info *ti; @@ -13,14 +26,12 @@ unsigned long *alloc_thread_stack_node(struct task_struct *task, int node) if (!ti) return NULL; - ti->exit_info = NULL; - ti->prev_sched = NULL; - ti->sched_sem = lkl_ops->sem_alloc(0); - ti->task = task; - if (!ti->sched_sem) { + if (init_ti(ti)) { kfree(ti); return NULL; } + ti->task = task; + return (unsigned long *)ti; } @@ -39,22 +50,21 @@ void setup_thread_stack(struct task_struct *p, struct task_struct *org) ti->addr_limit = org_ti->addr_limit; } -static void kill_thread(struct thread_exit_info *ei) +static void kill_thread(struct thread_info *ti) { - if (WARN_ON(!ei)) - return; + ti->dead = true; + lkl_ops->sem_up(ti->sched_sem); + lkl_ops->thread_join(ti->tid); + lkl_ops->sem_free(ti->sched_sem); - ei->dead = true; - lkl_ops->sem_up(ei->sched_sem); } void free_thread_stack(unsigned long *stack) { struct thread_info *ti = (struct thread_info *)stack; - struct thread_exit_info *ei = ti->exit_info; + kill_thread(ti); kfree(ti); - kill_thread(ei); } struct thread_info *_current_thread_info = &init_thread_union.thread_info; @@ -76,34 +86,19 @@ struct task_struct *__switch_to(struct task_struct *prev, * ksoftirqd0 -> swapper: returned prev is swapper */ static struct task_struct *abs_prev = &init_task; - /* - * We need to free the thread_info structure in free_thread_info to - * avoid races between the dying thread and other threads. We also need - * to cleanup sched_sem and signal to the prev thread that it needs to - * exit, and we use this stack varible to pass this info. - */ - struct thread_exit_info ei = { - .dead = false, - .sched_sem = _prev->sched_sem, - }; _current_thread_info = task_thread_info(next); _next->prev_sched = prev; abs_prev = prev; - _prev->exit_info = &ei; lkl_ops->sem_up(_next->sched_sem); - /* _next may be already gone so use ei instead */ - lkl_ops->sem_down(ei.sched_sem); + lkl_ops->sem_down(_prev->sched_sem); - if (ei.dead) { - lkl_ops->sem_free(ei.sched_sem); + if (_prev->dead) { __sync_fetch_and_sub(&threads_counter, 1); lkl_ops->thread_exit(); } - _prev->exit_info = NULL; - return abs_prev; } @@ -120,11 +115,6 @@ static void thread_bootstrap(void *_tba) int (*f)(void *) = tba->f; void *arg = tba->arg; - /* Our lifecycle is managed by the LKL kernel, so we want to - * detach here in order to free up host resources when we're - * killed */ - lkl_ops->thread_detach(); - lkl_ops->sem_down(ti->sched_sem); kfree(tba); if (ti->prev_sched) @@ -139,7 +129,6 @@ int copy_thread(unsigned long clone_flags, unsigned long esp, { struct thread_info *ti = task_thread_info(p); struct thread_bootstrap_arg *tba; - int ret; tba = kmalloc(sizeof(*tba), GFP_KERNEL); if (!tba) @@ -149,8 +138,8 @@ int copy_thread(unsigned long clone_flags, unsigned long esp, tba->arg = (void *)unused; tba->ti = ti; - ret = lkl_ops->thread_create(thread_bootstrap, tba); - if (!ret) { + ti->tid = lkl_ops->thread_create(thread_bootstrap, tba); + if (!ti->tid) { kfree(tba); return -ENOMEM; } @@ -177,16 +166,11 @@ static inline void pr_early(const char *str) int threads_init(void) { struct thread_info *ti = &init_thread_union.thread_info; - int ret = 0; - - ti->exit_info = NULL; - ti->prev_sched = NULL; + int ret; - ti->sched_sem = lkl_ops->sem_alloc(0); - if (!ti->sched_sem) { + ret = init_ti(ti); + if (ret < 0) pr_early("lkl: failed to allocate init schedule semaphore\n"); - ret = -ENOMEM; - } return ret; } @@ -204,7 +188,7 @@ void threads_cleanup(void) WARN(p->state == TASK_RUNNING, "thread %s still running while halting\n", p->comm); - kill_thread(ti->exit_info); + kill_thread(ti); } while (threads_counter)