summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/machine/tcb.c6
-rw-r--r--arch/x86/machine/tcb.h6
-rw-r--r--kern/thread.c28
3 files changed, 32 insertions, 8 deletions
diff --git a/arch/x86/machine/tcb.c b/arch/x86/machine/tcb.c
index e65eddf6..c6d4c7f1 100644
--- a/arch/x86/machine/tcb.c
+++ b/arch/x86/machine/tcb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013 Richard Braun.
+ * Copyright (c) 2012-2014 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
void __noreturn tcb_context_load(struct tcb *tcb);
void __noreturn tcb_start(void);
-void
+int
tcb_init(struct tcb *tcb, void *stack, void (*fn)(void))
{
void **ptr;
@@ -39,6 +39,8 @@ tcb_init(struct tcb *tcb, void *stack, void (*fn)(void))
ptr = (void **)tcb->sp;
*ptr = fn;
+
+ return 0;
}
void __init
diff --git a/arch/x86/machine/tcb.h b/arch/x86/machine/tcb.h
index b3785afe..79f953cb 100644
--- a/arch/x86/machine/tcb.h
+++ b/arch/x86/machine/tcb.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013 Richard Braun.
+ * Copyright (c) 2012-2014 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,8 +39,10 @@ struct tcb {
*
* Prepare the given stack for execution. The context is defined so that it
* will call fn() with interrupts disabled when loaded.
+ *
+ * In addition, initialize any thread-local machine-specific data.
*/
-void tcb_init(struct tcb *tcb, void *stack, void (*fn)(void));
+int tcb_init(struct tcb *tcb, void *stack, void (*fn)(void));
/*
* Low level context switch function.
diff --git a/kern/thread.c b/kern/thread.c
index ef340054..b66d7303 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -1421,13 +1421,14 @@ thread_init_sched(struct thread *thread, unsigned short priority)
thread_sched_ops[thread->sched_class].init_thread(thread, priority);
}
-static void
+static int
thread_init(struct thread *thread, void *stack, const struct thread_attr *attr,
void (*fn)(void *), void *arg)
{
struct thread *caller;
struct task *task;
struct cpumap *cpumap;
+ int error;
caller = thread_self();
@@ -1445,7 +1446,6 @@ thread_init(struct thread *thread, void *stack, const struct thread_attr *attr,
* Locking the run queue increases the preemption counter once more,
* making its value 2.
*/
- tcb_init(&thread->tcb, stack, thread_main);
thread->flags = 0;
thread->runq = NULL;
thread->state = THREAD_SLEEPING;
@@ -1462,7 +1462,18 @@ thread_init(struct thread *thread, void *stack, const struct thread_attr *attr,
thread->fn = fn;
thread->arg = arg;
+ /*
+ * This call may initialize thread-local data, do it once the thread is
+ * mostly initialized.
+ */
+ error = tcb_init(&thread->tcb, stack, thread_main);
+
+ if (error)
+ return error;
+
task_add_thread(task, thread);
+
+ return 0;
}
static struct thread_runq *
@@ -1712,7 +1723,11 @@ thread_setup_idler(struct thread_runq *runq)
thread_attr_init(&attr, name);
thread_attr_set_cpumap(&attr, cpumap);
thread_attr_set_policy(&attr, THREAD_SCHED_POLICY_IDLE);
- thread_init(idler, stack, &attr, thread_idle, runq);
+ error = thread_init(idler, stack, &attr, thread_idle, runq);
+
+ if (error)
+ panic("thread: unable to initialize idler thread");
+
cpumap_destroy(cpumap);
/* An idler thread needs special tuning */
@@ -1777,7 +1792,10 @@ thread_create(struct thread **threadp, const struct thread_attr *attr,
goto error_stack;
}
- thread_init(thread, stack, attr, fn, arg);
+ error = thread_init(thread, stack, attr, fn, arg);
+
+ if (error)
+ goto error_init;
/*
* The new thread address must be written before the thread is started
@@ -1789,6 +1807,8 @@ thread_create(struct thread **threadp, const struct thread_attr *attr,
return 0;
+error_init:
+ kmem_cache_free(&thread_stack_cache, stack);
error_stack:
kmem_cache_free(&thread_cache, thread);
error_thread: