mirror of
https://github.com/drasko/codezero.git
synced 2026-09-28 16:20:21 +02:00
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.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Address allocation pool
|
* Address allocation pool.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
* Copyright (C) 2007 Bahadir Balban
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
* Stack region helper routines.
|
* Stack space helper routines.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 B Labs Ltd.
|
* Copyright (C) 2009 B Labs Ltd.
|
||||||
*/
|
*/
|
||||||
#ifndef __LIB_STACK_H__
|
#ifndef __LIB_STACK_H__
|
||||||
#define __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)
|
#define IS_STACK_SETUP() (lib_stack_size)
|
||||||
|
|
||||||
int stack_pool_init(unsigned long stack_start,
|
int stack_pool_init(unsigned long stack_start,
|
||||||
unsigned long stack_end,
|
unsigned long stack_end,
|
||||||
unsigned long stack_size);
|
unsigned long stack_size);
|
||||||
|
|
||||||
void *get_stack_space(int nitems, int size);
|
void *get_stack_space(void);
|
||||||
int delete_stack_space(void *stack_address, int nitems, int size);
|
int delete_stack_space(void *stack_address);
|
||||||
|
|
||||||
#endif /* __LIB_STACK_H__ */
|
#endif /* __LIB_STACK_H__ */
|
||||||
|
|||||||
@@ -14,23 +14,30 @@ struct utcb_head {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* A simple thread control block for the thread library. */
|
/* A simple thread control block for the thread library. */
|
||||||
struct l4t_tcb {
|
struct tcb {
|
||||||
|
/* Task list */
|
||||||
struct link list;
|
struct link list;
|
||||||
|
|
||||||
|
/* Task id */
|
||||||
int tid;
|
int tid;
|
||||||
|
|
||||||
|
/* Chain of utcb descriptors */
|
||||||
struct utcb_head *utcb_head;
|
struct utcb_head *utcb_head;
|
||||||
|
|
||||||
|
/* Stack and utcb address */
|
||||||
unsigned long utcb_addr;
|
unsigned long utcb_addr;
|
||||||
unsigned long stack_addr;
|
unsigned long stack_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This struct keeps track of all the threads handled by the thread lib. */
|
/* All the threads handled by the thread lib are kept in this list. */
|
||||||
struct l4t_global_list {
|
struct global_list {
|
||||||
int total;
|
int total;
|
||||||
struct link list;
|
struct link list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct l4t_tcb *l4t_find_task(int tid);
|
struct tcb *find_task(int tid);
|
||||||
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);
|
||||||
void l4t_global_add_task(struct l4t_tcb *task);
|
void global_add_task(struct tcb *task);
|
||||||
void l4t_global_remove_task(struct l4t_tcb *task);
|
void global_remove_task(struct tcb *task);
|
||||||
|
|
||||||
#endif /* __LIB_TCB_H__ */
|
#endif /* __LIB_TCB_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_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end);
|
||||||
|
|
||||||
int l4_thread_create(struct task_ids *ids, unsigned int flags,
|
int l4_thread_create(struct task_ids *ids, unsigned int flags,
|
||||||
void *(*func)(void *), void *arg);
|
int (*func)(void *), void *arg);
|
||||||
void l4_thread_exit(void *retval);
|
void l4_thread_exit(int retval);
|
||||||
|
|
||||||
#endif /* __LIB_THREAD_H__ */
|
#endif /* __LIB_THREAD_H__ */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* UTCB handling helper routines
|
* UTCB handling helper routines.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 B Labs Ltd.
|
* Copyright (C) 2009 B Labs Ltd.
|
||||||
*/
|
*/
|
||||||
@@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
#include <tcb.h>
|
#include <tcb.h>
|
||||||
|
|
||||||
unsigned long get_utcb_addr(struct l4t_tcb *task);
|
/* Checks if l4_set_stack_params is called. */
|
||||||
int delete_utcb_addr(struct l4t_tcb *task);
|
#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__ */
|
#endif /* __LIB_UTCB_H__ */
|
||||||
|
|||||||
@@ -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.
|
* Copyright (C) 2009 B Labs Ltd.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ int stack_pool_init(unsigned long stack_start,
|
|||||||
return 0;
|
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,
|
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)
|
unsigned long stack_size)
|
||||||
{
|
{
|
||||||
/* Ensure that arguments are valid. */
|
/* 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()) {
|
if (IS_STACK_SETUP()) {
|
||||||
printf("libl4thread: You have already called: %s.\n",
|
printf("libl4thread: You have already called: %s.\n",
|
||||||
__FUNCTION__);
|
__FUNCTION__);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
if (!stack_top || !stack_bottom) {
|
if (!stack_top || !stack_bottom) {
|
||||||
@@ -87,12 +85,11 @@ int l4_set_stack_params(unsigned long stack_top,
|
|||||||
/* Initialize internal variables. */
|
/* Initialize internal variables. */
|
||||||
lib_stack_size = stack_size;
|
lib_stack_size = stack_size;
|
||||||
|
|
||||||
/* Init stack virtual address pool. */
|
/* Initialize stack virtual address pool. */
|
||||||
stack_pool_init(stack_top, stack_bottom, stack_size);
|
if (stack_pool_init(stack_top, stack_bottom, stack_size) < 0)
|
||||||
|
BUG();
|
||||||
|
|
||||||
/* Init the global mutex. */
|
/* Initialize the global mutex. */
|
||||||
//FIXME: Ensure that l4thread_create will not be called
|
|
||||||
// before the mutex is initialized.
|
|
||||||
l4_mutex_init(&lib_mutex);
|
l4_mutex_init(&lib_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+23
-15
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Thread management in libl4thread.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 B Labs Ltd.
|
||||||
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <malloc/malloc.h>
|
#include <malloc/malloc.h>
|
||||||
#include <l4/api/errno.h>
|
#include <l4/api/errno.h>
|
||||||
@@ -5,50 +10,53 @@
|
|||||||
#include <tcb.h>
|
#include <tcb.h>
|
||||||
|
|
||||||
/* Global task list. */
|
/* Global task list. */
|
||||||
struct l4t_global_list l4t_global_tasks = {
|
struct global_list global_tasks = {
|
||||||
.list = { &l4t_global_tasks.list, &l4t_global_tasks.list },
|
.list = { &global_tasks.list, &global_tasks.list },
|
||||||
.total = 0,
|
.total = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Function definitions */
|
/* Function definitions */
|
||||||
void l4t_global_add_task(struct l4t_tcb *task)
|
void global_add_task(struct tcb *task)
|
||||||
{
|
{
|
||||||
BUG_ON(!list_empty(&task->list));
|
BUG_ON(!list_empty(&task->list));
|
||||||
list_insert_tail(&task->list, &l4t_global_tasks.list);
|
list_insert_tail(&task->list, &global_tasks.list);
|
||||||
l4t_global_tasks.total++;
|
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));
|
BUG_ON(list_empty(&task->list));
|
||||||
list_remove_init(&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)
|
if (t->tid == tid)
|
||||||
return t;
|
return t;
|
||||||
return 0;
|
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);
|
return PTR_ERR(-ENOMEM);
|
||||||
|
|
||||||
link_init(&task->list);
|
link_init(&task->list);
|
||||||
|
|
||||||
if ((parent) && (flags & TC_SHARE_SPACE))
|
if (flags & TC_SHARE_SPACE)
|
||||||
task->utcb_head = parent->utcb_head;
|
task->utcb_head = parent->utcb_head;
|
||||||
else {
|
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);
|
return PTR_ERR(-ENOMEM);
|
||||||
|
}
|
||||||
link_init(&task->utcb_head->list);
|
link_init(&task->utcb_head->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,76 +17,70 @@
|
|||||||
/* Extern declarations */
|
/* Extern declarations */
|
||||||
extern void setup_new_thread(void);
|
extern void setup_new_thread(void);
|
||||||
extern unsigned long lib_stack_size;
|
extern unsigned long lib_stack_size;
|
||||||
|
extern unsigned long lib_utcb_range_size;
|
||||||
|
|
||||||
/* Static variable definitions */
|
/* Static variable definitions */
|
||||||
struct l4_mutex lib_mutex;
|
struct l4_mutex lib_mutex;
|
||||||
|
|
||||||
/* Function definitions */
|
/* Function definitions */
|
||||||
int l4_thread_create(struct task_ids *ids, unsigned int flags,
|
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;
|
struct exregs_data exregs;
|
||||||
unsigned long utcb_addr;
|
unsigned long utcb_addr;
|
||||||
struct l4t_tcb *parent, *child;
|
struct tcb *parent, *child;
|
||||||
int err;
|
|
||||||
unsigned long stack_top_addr, stack_bot_addr;
|
unsigned long stack_top_addr, stack_bot_addr;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
/* A few controls before granting access to thread creation */
|
/* A few controls before granting access to thread creation */
|
||||||
// FIXME: check if utcb region is setup
|
if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) {
|
||||||
if (!IS_STACK_SETUP()) {
|
|
||||||
printf("libl4thread: Stack and/or utcb have not been "
|
printf("libl4thread: Stack and/or utcb have not been "
|
||||||
"set up.\n");
|
"set up.\n");
|
||||||
return -EPERM;
|
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. */
|
/* Before doing any operation get the global mutex. */
|
||||||
l4_mutex_lock(&lib_mutex);
|
l4_mutex_lock(&lib_mutex);
|
||||||
|
|
||||||
/* Get parent's ids and find the tcb belonging to it. */
|
/* Get parent's ids and find the tcb belonging to it. */
|
||||||
l4_getid(ids);
|
l4_getid(ids);
|
||||||
if (!(parent = l4t_find_task(ids->tid)))
|
if (!(parent = find_task(ids->tid))) {
|
||||||
return-ESRCH;
|
err = -ESRCH;
|
||||||
|
goto out_err1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate tcb for the child. */
|
/* 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");
|
printf("libl4thread: No heap space left.\n");
|
||||||
return -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
goto out_err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a utcb addr. */
|
/* Get a utcb addr. */
|
||||||
if (!(utcb_addr = get_utcb_addr(child))) {
|
if (!(utcb_addr = get_utcb_addr(child))) {
|
||||||
printf("libl4thread: No utcb address left.\n");
|
printf("libl4thread: No utcb space left.\n");
|
||||||
// FIXME: Check if there is any memory leak
|
err = -ENOMEM;
|
||||||
kfree(child);
|
goto out_err2;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
/* Create thread */
|
||||||
if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) {
|
if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) {
|
||||||
printf("libl4thread: l4_thread_control(THREAD_CREATE) "
|
printf("libl4thread: l4_thread_control(THREAD_CREATE) "
|
||||||
"failed with (%d).\n", err);
|
"failed with (%d).\n", err);
|
||||||
// FIXME: Check if there is any memory leak
|
goto out_err4;
|
||||||
kfree(child);
|
|
||||||
delete_utcb_addr(child);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
/* Setup new thread pc, sp, utcb */
|
||||||
memset(&exregs, 0, sizeof(exregs));
|
memset(&exregs, 0, sizeof(exregs));
|
||||||
exregs_set_stack(&exregs, align((stack_bot_addr - 1), 8));
|
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) {
|
if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) {
|
||||||
printf("libl4thread: l4_exchange_registers failed with "
|
printf("libl4thread: l4_exchange_registers failed with "
|
||||||
"(%d).\n", err);
|
"(%d).\n", err);
|
||||||
// FIXME: Check if there is any memory leak
|
goto out_err5;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First word of new stack is arg */
|
/* 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 */
|
/* Add child to the global task list */
|
||||||
child->tid = ids->tid;
|
child->tid = ids->tid;
|
||||||
l4t_global_add_task(child);
|
global_add_task(child);
|
||||||
|
|
||||||
/* Start the new thread */
|
/* Start the new thread */
|
||||||
if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) {
|
if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) {
|
||||||
// FIXME: Check if there is any memory leak
|
|
||||||
printf("libl4thread: l4_thread_control(THREAD_RUN) "
|
printf("libl4thread: l4_thread_control(THREAD_RUN) "
|
||||||
"failed with (%d).\n", err);
|
"failed with (%d).\n", err);
|
||||||
return err;
|
goto out_err6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the global mutex. */
|
/* Release the global mutex. */
|
||||||
l4_mutex_unlock(&lib_mutex);
|
l4_mutex_unlock(&lib_mutex);
|
||||||
|
|
||||||
return 0;
|
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;
|
struct task_ids ids;
|
||||||
|
|
||||||
/* Before doing any operation get the global mutex. */
|
/* Before doing any operation get the global mutex. */
|
||||||
@@ -136,26 +146,28 @@ void l4_thread_exit(void *retval)
|
|||||||
/* Find the task. */
|
/* Find the task. */
|
||||||
l4_getid(&ids);
|
l4_getid(&ids);
|
||||||
/* Cant find the thread means it wasnt added to the list. */
|
/* 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();
|
BUG();
|
||||||
|
|
||||||
/* Delete the utcb address. */
|
/* Delete the utcb address. */
|
||||||
delete_utcb_addr(task);
|
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: We assume that main thread never leaves the scene
|
||||||
|
// FIXME: What happens to task->utcb_head?
|
||||||
kfree(task);
|
kfree(task);
|
||||||
|
|
||||||
/* Release the global mutex. */
|
/* Release the global mutex. */
|
||||||
l4_mutex_unlock(&lib_mutex);
|
l4_mutex_unlock(&lib_mutex);
|
||||||
|
|
||||||
/* Relinquish the control. */
|
/* Relinquish the control. */
|
||||||
l4_exit(*(unsigned int *)retval);
|
l4_exit(retval);
|
||||||
|
|
||||||
/* Should never reach here. */
|
/* Should never reach here. */
|
||||||
BUG();
|
BUG();
|
||||||
@@ -163,27 +175,29 @@ void l4_thread_exit(void *retval)
|
|||||||
|
|
||||||
int l4_thread_kill(struct task_ids *ids)
|
int l4_thread_kill(struct task_ids *ids)
|
||||||
{
|
{
|
||||||
struct l4t_tcb *task;
|
struct tcb *task;
|
||||||
|
|
||||||
/* Before doing any operation get the global mutex. */
|
/* Before doing any operation get the global mutex. */
|
||||||
l4_mutex_lock(&lib_mutex);
|
l4_mutex_lock(&lib_mutex);
|
||||||
|
|
||||||
/* Find the task to be killed. */
|
/* Find the task to be killed. */
|
||||||
if (!(task = l4t_find_task(ids->tid))) {
|
if (!(task = find_task(ids->tid))) {
|
||||||
l4_mutex_unlock(&lib_mutex);
|
l4_mutex_unlock(&lib_mutex);
|
||||||
return -ESRCH;
|
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 the utcb address. */
|
||||||
delete_utcb_addr(task);
|
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: We assume that main thread never leaves the scene
|
||||||
|
// FIXME: What happens to task->utcb_head?
|
||||||
kfree(task);
|
kfree(task);
|
||||||
|
|
||||||
/* Release the global mutex. */
|
/* Release the global mutex. */
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end)
|
|||||||
/* Initialise the global utcb virtual address pool */
|
/* Initialise the global utcb virtual address pool */
|
||||||
if ((err = address_pool_init(&utcb_region_pool,
|
if ((err = address_pool_init(&utcb_region_pool,
|
||||||
utcb_start, utcb_end,
|
utcb_start, utcb_end,
|
||||||
UTCB_SIZE) < 0)) {
|
PAGE_SIZE) < 0)) {
|
||||||
printf("UTCB address pool initialisation failed.\n");
|
printf("UTCB address pool initialisation failed.\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,11 @@ struct utcb_desc *utcb_new_desc(void)
|
|||||||
|
|
||||||
/* Obtain a new and unique utcb base */
|
/* Obtain a new and unique utcb base */
|
||||||
/* FIXME: Use variable size than a page */
|
/* 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;
|
return d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* UTCB handling helper routines
|
* UTCB handling helper routines.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 B Labs Ltd.
|
* Copyright (C) 2009 B Labs Ltd.
|
||||||
*/
|
*/
|
||||||
@@ -13,10 +13,13 @@
|
|||||||
#include <utcb.h>
|
#include <utcb.h>
|
||||||
|
|
||||||
/* Extern declarations */
|
/* 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 */
|
/* Function definitions */
|
||||||
unsigned long get_utcb_addr(struct l4t_tcb *task)
|
unsigned long get_utcb_addr(struct tcb *task)
|
||||||
{
|
{
|
||||||
struct utcb_desc *udesc;
|
struct utcb_desc *udesc;
|
||||||
unsigned long slot;
|
unsigned long slot;
|
||||||
@@ -30,7 +33,8 @@ unsigned long get_utcb_addr(struct l4t_tcb *task)
|
|||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
/* Allocate a new utcb memory region and return its base. */
|
/* 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);
|
slot = utcb_new_slot(udesc);
|
||||||
list_insert(&udesc->list, &task->utcb_head->list);
|
list_insert(&udesc->list, &task->utcb_head->list);
|
||||||
found:
|
found:
|
||||||
@@ -39,7 +43,7 @@ found:
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
int delete_utcb_addr(struct l4t_tcb *task)
|
int delete_utcb_addr(struct tcb *task)
|
||||||
{
|
{
|
||||||
struct utcb_desc *udesc;
|
struct utcb_desc *udesc;
|
||||||
|
|
||||||
@@ -68,29 +72,31 @@ static int set_utcb_addr(void)
|
|||||||
{
|
{
|
||||||
struct exregs_data exregs;
|
struct exregs_data exregs;
|
||||||
struct task_ids ids;
|
struct task_ids ids;
|
||||||
struct l4t_tcb *task;
|
struct tcb *task;
|
||||||
struct utcb_desc *udesc;
|
struct utcb_desc *udesc;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Create a task. */
|
/* Create a task. */
|
||||||
if (IS_ERR(task = l4t_tcb_alloc_init(0, 0)))
|
if (IS_ERR(task = tcb_alloc_init(0, 0)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Add child to the global task list. */
|
/* Add child to the global task list. */
|
||||||
list_insert_tail(&task->list, &l4t_global_tasks.list);
|
list_insert_tail(&task->list, &global_tasks.list);
|
||||||
l4t_global_tasks.total++;
|
global_tasks.total++;
|
||||||
|
|
||||||
udesc = utcb_new_desc();
|
if (!(udesc = utcb_new_desc()))
|
||||||
|
return -ENOMEM;
|
||||||
task->utcb_addr = utcb_new_slot(udesc);
|
task->utcb_addr = utcb_new_slot(udesc);
|
||||||
list_insert(&udesc->list, &task->utcb_head->list);
|
list_insert(&udesc->list, &task->utcb_head->list);
|
||||||
|
|
||||||
memset(&exregs, 0, sizeof(exregs));
|
memset(&exregs, 0, sizeof(exregs));
|
||||||
exregs_set_utcb(&exregs, (unsigned long)task->utcb_addr);
|
exregs_set_utcb(&exregs, task->utcb_addr);
|
||||||
|
|
||||||
l4_getid(&ids);
|
l4_getid(&ids);
|
||||||
|
task->tid = ids.tid;
|
||||||
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) {
|
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) {
|
||||||
printf("libl4thread: l4_exchange_registers failed with "
|
printf("libl4thread: l4_exchange_registers failed with "
|
||||||
"(%d).\n", err);
|
"(%d).\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,21 +108,20 @@ int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Ensure that arguments are valid. */
|
/* Ensure that arguments are valid. */
|
||||||
// FIXME: Check if set_utcb_params is called
|
if (IS_UTCB_SETUP()) {
|
||||||
/*if (IS_UTCB_SETUP()) {*/
|
printf("libl4thread: You have already called: %s.\n",
|
||||||
/*printf("libl4thread: You have already called: %s.\n",*/
|
__FUNCTION__);
|
||||||
/*__FUNCTION__);*/
|
return -EPERM;
|
||||||
/*return -EPERM;*/
|
}
|
||||||
/*}*/
|
|
||||||
if (!utcb_start || !utcb_end) {
|
if (!utcb_start || !utcb_end) {
|
||||||
printf("libl4thread: Utcb address range cannot contain "
|
printf("libl4thread: Utcb address range cannot contain "
|
||||||
"0x0 as a start and/or end address(es).\n");
|
"0x0 as a start and/or end address(es).\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* Check if the start address is aligned on UTCB_SIZE. */
|
/* Check if the start address is aligned on PAGE_SIZE. */
|
||||||
if (utcb_start & !UTCB_SIZE) {
|
if (utcb_start & PAGE_MASK) {
|
||||||
printf("libl4thread: Utcb start address must be aligned "
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* The range must be a valid one. */
|
/* 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. */
|
/* Arguments passed the validity tests. */
|
||||||
|
|
||||||
/* Init utcb virtual address pool. */
|
/* 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)
|
if ((err = set_utcb_addr()) < 0)
|
||||||
return err;
|
BUG();
|
||||||
|
|
||||||
|
/* Initialize internal variables. */
|
||||||
|
lib_utcb_range_size = utcb_end - utcb_start;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user