diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2010-06-18 03:10:18 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2010-06-18 03:10:18 +0000 |
commit | d9c9fe305c01c30e4f9e8c981a7069ef8e94ca81 (patch) | |
tree | 3bc6a8e7e36e5f3fb9e429b331f15c769542d738 | |
parent | b812465bfff2111e149a44d7041c1d62d7e1519c (diff) | |
download | rockbox-d9c9fe305c01c30e4f9e8c981a7069ef8e94ca81.tar.gz rockbox-d9c9fe305c01c30e4f9e8c981a7069ef8e94ca81.zip |
For multiprocessor targets, do the thread_exit routine such that we don't need to rely on the compiler's good graces to have stack switching be reliable. Only needs a few asm instructions.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26906 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/target/arm/thread-pp.c | 25 | ||||
-rw-r--r-- | firmware/thread.c | 25 |
2 files changed, 29 insertions, 21 deletions
diff --git a/firmware/target/arm/thread-pp.c b/firmware/target/arm/thread-pp.c index 335f1f3e0a..0c077779e5 100644 --- a/firmware/target/arm/thread-pp.c +++ b/firmware/target/arm/thread-pp.c | |||
@@ -199,7 +199,9 @@ static void INIT_ATTR core_thread_init(unsigned int core) | |||
199 | } | 199 | } |
200 | 200 | ||
201 | /*--------------------------------------------------------------------------- | 201 | /*--------------------------------------------------------------------------- |
202 | * Switches to a stack that always resides in the Rockbox core. | 202 | * Switches to a stack that always resides in the Rockbox core then calls |
203 | * the final exit routine to actually finish removing the thread from the | ||
204 | * scheduler. | ||
203 | * | 205 | * |
204 | * Needed when a thread suicides on a core other than the main CPU since the | 206 | * Needed when a thread suicides on a core other than the main CPU since the |
205 | * stack used when idling is the stack of the last thread to run. This stack | 207 | * stack used when idling is the stack of the last thread to run. This stack |
@@ -207,13 +209,24 @@ static void INIT_ATTR core_thread_init(unsigned int core) | |||
207 | * to use a stack from an unloaded module until another thread runs on it. | 209 | * to use a stack from an unloaded module until another thread runs on it. |
208 | *--------------------------------------------------------------------------- | 210 | *--------------------------------------------------------------------------- |
209 | */ | 211 | */ |
210 | static inline void switch_to_idle_stack(const unsigned int core) | 212 | static inline void __attribute__((noreturn,always_inline)) |
213 | thread_final_exit(struct thread_entry *current) | ||
211 | { | 214 | { |
212 | asm volatile ( | 215 | asm volatile ( |
213 | "str sp, [%0] \n" /* save original stack pointer on idle stack */ | 216 | "cmp %1, #0 \n" /* CPU? */ |
214 | "mov sp, %0 \n" /* switch stacks */ | 217 | "ldrne r0, =cpucache_flush \n" /* No? write back data */ |
215 | : : "r"(&idle_stacks[core][IDLE_STACK_WORDS-1])); | 218 | "movne lr, pc \n" |
216 | (void)core; | 219 | "bxne r0 \n" |
220 | "mov r0, %0 \n" /* copy thread parameter */ | ||
221 | "mov sp, %2 \n" /* switch to idle stack */ | ||
222 | "bl thread_final_exit_do \n" /* finish removal */ | ||
223 | : : "r"(current), | ||
224 | "r"(current->core), | ||
225 | "r"(&idle_stacks[current->core][IDLE_STACK_WORDS]) | ||
226 | : "r0", "r1", "r2", "r3", "ip", "lr"); /* Because of flush call, | ||
227 | force inputs out | ||
228 | of scratch regs */ | ||
229 | while (1); | ||
217 | } | 230 | } |
218 | 231 | ||
219 | /*--------------------------------------------------------------------------- | 232 | /*--------------------------------------------------------------------------- |
diff --git a/firmware/thread.c b/firmware/thread.c index de9d05da88..c00fc36e3f 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -157,8 +157,8 @@ static inline void load_context(const void* addr) | |||
157 | __attribute__((always_inline)); | 157 | __attribute__((always_inline)); |
158 | 158 | ||
159 | #if NUM_CORES > 1 | 159 | #if NUM_CORES > 1 |
160 | static void thread_final_exit(struct thread_entry *current) | 160 | static void thread_final_exit_do(struct thread_entry *current) |
161 | __attribute__((noinline, noreturn)); | 161 | __attribute__((noinline, noreturn, used)); |
162 | #else | 162 | #else |
163 | static inline void thread_final_exit(struct thread_entry *current) | 163 | static inline void thread_final_exit(struct thread_entry *current) |
164 | __attribute__((always_inline, noreturn)); | 164 | __attribute__((always_inline, noreturn)); |
@@ -1675,22 +1675,16 @@ void thread_wait(unsigned int thread_id) | |||
1675 | /* This is done to foil optimizations that may require the current stack, | 1675 | /* This is done to foil optimizations that may require the current stack, |
1676 | * such as optimizing subexpressions that put variables on the stack that | 1676 | * such as optimizing subexpressions that put variables on the stack that |
1677 | * get used after switching stacks. */ | 1677 | * get used after switching stacks. */ |
1678 | static void thread_final_exit(struct thread_entry *current) | ||
1679 | { | ||
1680 | #if NUM_CORES > 1 | 1678 | #if NUM_CORES > 1 |
1681 | cpucache_flush(); | 1679 | /* Called by ASM stub */ |
1682 | 1680 | static void thread_final_exit_do(struct thread_entry *current) | |
1683 | /* Switch to the idle stack if not on the main core (where "main" | 1681 | #else |
1684 | * runs) - we can hope gcc doesn't need the old stack beyond this | 1682 | /* No special procedure is required before calling */ |
1685 | * point. */ | 1683 | static inline void thread_final_exit(struct thread_entry *current) |
1686 | if (current->core != CPU) | 1684 | #endif |
1687 | { | 1685 | { |
1688 | switch_to_idle_stack(current->core); | ||
1689 | } | ||
1690 | |||
1691 | /* At this point, this thread isn't using resources allocated for | 1686 | /* At this point, this thread isn't using resources allocated for |
1692 | * execution except the slot itself. */ | 1687 | * execution except the slot itself. */ |
1693 | #endif /* NUM_CORES */ | ||
1694 | 1688 | ||
1695 | /* Signal this thread */ | 1689 | /* Signal this thread */ |
1696 | thread_queue_wake(¤t->queue); | 1690 | thread_queue_wake(¤t->queue); |
@@ -1746,6 +1740,7 @@ void thread_exit(void) | |||
1746 | new_thread_id(current->id, current); | 1740 | new_thread_id(current->id, current); |
1747 | current->name = NULL; | 1741 | current->name = NULL; |
1748 | 1742 | ||
1743 | /* Do final cleanup and remove the thread */ | ||
1749 | thread_final_exit(current); | 1744 | thread_final_exit(current); |
1750 | } | 1745 | } |
1751 | 1746 | ||