summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2014-05-06 20:49:26 +0200
committerRichard Braun <rbraun@sceen.net>2014-05-06 20:49:26 +0200
commitb11e4e9411cb0a4e99c370a4ff9a275540036aae (patch)
tree72064536d69b40727b1309f78da341b456a3c8f5
parentedae23a2cd2800dff9806309854fb46f12d408d7 (diff)
x86/tcb: make tcb_init initialize thread-local data
For now, there is no thread-local data to actually initialize, but the interface is there to allow it. The main goal of this change is to avoid the need of complex startup synchronization by allocating thread-local data at thread creation time.
-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: