summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/target/arm/thread-pp.c25
-rw-r--r--firmware/thread.c25
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 */
210static inline void switch_to_idle_stack(const unsigned int core) 212static 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
160static void thread_final_exit(struct thread_entry *current) 160static void thread_final_exit_do(struct thread_entry *current)
161 __attribute__((noinline, noreturn)); 161 __attribute__((noinline, noreturn, used));
162#else 162#else
163static inline void thread_final_exit(struct thread_entry *current) 163static 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. */
1678static 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 1680static 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. */ 1683static 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(&current->queue); 1690 thread_queue_wake(&current->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