diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/thread.h | 2 | ||||
-rw-r--r-- | firmware/target/hosted/sdl/thread-sdl.c | 5 | ||||
-rw-r--r-- | firmware/thread.c | 72 |
3 files changed, 51 insertions, 28 deletions
diff --git a/firmware/export/thread.h b/firmware/export/thread.h index 8912283343..d907e5dc95 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h | |||
@@ -375,7 +375,7 @@ void thread_thaw(unsigned int thread_id); | |||
375 | /* Wait for a thread to exit */ | 375 | /* Wait for a thread to exit */ |
376 | void thread_wait(unsigned int thread_id); | 376 | void thread_wait(unsigned int thread_id); |
377 | /* Exit the current thread */ | 377 | /* Exit the current thread */ |
378 | void thread_exit(void); | 378 | void thread_exit(void) __attribute__((noreturn)); |
379 | #if defined(DEBUG) || defined(ROCKBOX_HAS_LOGF) | 379 | #if defined(DEBUG) || defined(ROCKBOX_HAS_LOGF) |
380 | #define ALLOW_REMOVE_THREAD | 380 | #define ALLOW_REMOVE_THREAD |
381 | /* Remove a thread from the scheduler */ | 381 | /* Remove a thread from the scheduler */ |
diff --git a/firmware/target/hosted/sdl/thread-sdl.c b/firmware/target/hosted/sdl/thread-sdl.c index 5ef9867b23..1a683911d7 100644 --- a/firmware/target/hosted/sdl/thread-sdl.c +++ b/firmware/target/hosted/sdl/thread-sdl.c | |||
@@ -630,6 +630,11 @@ void remove_thread(unsigned int thread_id) | |||
630 | void thread_exit(void) | 630 | void thread_exit(void) |
631 | { | 631 | { |
632 | remove_thread(THREAD_ID_CURRENT); | 632 | remove_thread(THREAD_ID_CURRENT); |
633 | /* This should never and must never be reached - if it is, the | ||
634 | * state is corrupted */ | ||
635 | THREAD_PANICF("thread_exit->K:*R", | ||
636 | thread_id_entry(THREAD_ID_CURRENT)); | ||
637 | while (1); | ||
633 | } | 638 | } |
634 | 639 | ||
635 | void thread_wait(unsigned int thread_id) | 640 | void thread_wait(unsigned int thread_id) |
diff --git a/firmware/thread.c b/firmware/thread.c index 5cad67b657..48734f2ffe 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -156,6 +156,14 @@ static inline void store_context(void* addr) | |||
156 | static inline void load_context(const void* addr) | 156 | static inline void load_context(const void* addr) |
157 | __attribute__((always_inline)); | 157 | __attribute__((always_inline)); |
158 | 158 | ||
159 | #if NUM_CORES > 1 | ||
160 | static void __attribute__((noinline, noreturn)) | ||
161 | thread_final_exit(struct thread_entry *current); | ||
162 | #else | ||
163 | static void __attribute__((always_inline, noreturn)) | ||
164 | thread_final_exit(struct thread_entry *current); | ||
165 | #endif | ||
166 | |||
159 | void switch_thread(void) | 167 | void switch_thread(void) |
160 | __attribute__((noinline)); | 168 | __attribute__((noinline)); |
161 | 169 | ||
@@ -219,7 +227,7 @@ static void thread_stkov(struct thread_entry *thread) | |||
219 | #define LOCK_THREAD(thread) \ | 227 | #define LOCK_THREAD(thread) \ |
220 | ({ corelock_lock(&(thread)->slot_cl); }) | 228 | ({ corelock_lock(&(thread)->slot_cl); }) |
221 | #define TRY_LOCK_THREAD(thread) \ | 229 | #define TRY_LOCK_THREAD(thread) \ |
222 | ({ corelock_try_lock(&thread->slot_cl); }) | 230 | ({ corelock_try_lock(&(thread)->slot_cl); }) |
223 | #define UNLOCK_THREAD(thread) \ | 231 | #define UNLOCK_THREAD(thread) \ |
224 | ({ corelock_unlock(&(thread)->slot_cl); }) | 232 | ({ corelock_unlock(&(thread)->slot_cl); }) |
225 | #define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \ | 233 | #define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \ |
@@ -854,7 +862,8 @@ struct thread_entry * | |||
854 | * catch something. | 862 | * catch something. |
855 | *--------------------------------------------------------------------------- | 863 | *--------------------------------------------------------------------------- |
856 | */ | 864 | */ |
857 | static void check_for_obj_waiters(const char *function, struct thread_entry *thread) | 865 | static void __attribute__((noinline)) check_for_obj_waiters( |
866 | const char *function, struct thread_entry *thread) | ||
858 | { | 867 | { |
859 | /* Only one bit in the mask should be set with a frequency on 1 which | 868 | /* Only one bit in the mask should be set with a frequency on 1 which |
860 | * represents the thread's own base priority */ | 869 | * represents the thread's own base priority */ |
@@ -1663,10 +1672,39 @@ void thread_wait(unsigned int thread_id) | |||
1663 | * Exit the current thread. The Right Way to Do Things (TM). | 1672 | * Exit the current thread. The Right Way to Do Things (TM). |
1664 | *--------------------------------------------------------------------------- | 1673 | *--------------------------------------------------------------------------- |
1665 | */ | 1674 | */ |
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 | ||
1677 | * get used after switching stacks. */ | ||
1678 | static void thread_final_exit(struct thread_entry *current) | ||
1679 | { | ||
1680 | #if NUM_CORES > 1 | ||
1681 | cpucache_flush(); | ||
1682 | |||
1683 | /* Switch to the idle stack if not on the main core (where "main" | ||
1684 | * runs) - we can hope gcc doesn't need the old stack beyond this | ||
1685 | * point. */ | ||
1686 | if (current->core != CPU) | ||
1687 | { | ||
1688 | switch_to_idle_stack(current->core); | ||
1689 | } | ||
1690 | |||
1691 | /* At this point, this thread isn't using resources allocated for | ||
1692 | * execution except the slot itself. */ | ||
1693 | #endif /* NUM_CORES */ | ||
1694 | |||
1695 | /* Signal this thread */ | ||
1696 | thread_queue_wake(¤t->queue); | ||
1697 | corelock_unlock(¤t->waiter_cl); | ||
1698 | switch_thread(); | ||
1699 | /* This should never and must never be reached - if it is, the | ||
1700 | * state is corrupted */ | ||
1701 | THREAD_PANICF("thread_exit->K:*R", current); | ||
1702 | while (1); | ||
1703 | } | ||
1704 | |||
1666 | void thread_exit(void) | 1705 | void thread_exit(void) |
1667 | { | 1706 | { |
1668 | const unsigned int core = CURRENT_CORE; | 1707 | register struct thread_entry * current = cores[CURRENT_CORE].running; |
1669 | struct thread_entry *current = cores[core].running; | ||
1670 | 1708 | ||
1671 | /* Cancel CPU boost if any */ | 1709 | /* Cancel CPU boost if any */ |
1672 | cancel_cpu_boost(); | 1710 | cancel_cpu_boost(); |
@@ -1701,34 +1739,14 @@ void thread_exit(void) | |||
1701 | /* Switch tasks and never return */ | 1739 | /* Switch tasks and never return */ |
1702 | block_thread_on_l(current, STATE_KILLED); | 1740 | block_thread_on_l(current, STATE_KILLED); |
1703 | 1741 | ||
1704 | #if NUM_CORES > 1 | 1742 | /* Slot must be unusable until thread is really gone */ |
1705 | /* Switch to the idle stack if not on the main core (where "main" | 1743 | UNLOCK_THREAD_AT_TASK_SWITCH(current); |
1706 | * runs) - we can hope gcc doesn't need the old stack beyond this | ||
1707 | * point. */ | ||
1708 | if (core != CPU) | ||
1709 | { | ||
1710 | switch_to_idle_stack(core); | ||
1711 | } | ||
1712 | |||
1713 | cpucache_flush(); | ||
1714 | |||
1715 | /* At this point, this thread isn't using resources allocated for | ||
1716 | * execution except the slot itself. */ | ||
1717 | #endif | ||
1718 | 1744 | ||
1719 | /* Update ID for this slot */ | 1745 | /* Update ID for this slot */ |
1720 | new_thread_id(current->id, current); | 1746 | new_thread_id(current->id, current); |
1721 | current->name = NULL; | 1747 | current->name = NULL; |
1722 | 1748 | ||
1723 | /* Signal this thread */ | 1749 | thread_final_exit(current); |
1724 | thread_queue_wake(¤t->queue); | ||
1725 | corelock_unlock(¤t->waiter_cl); | ||
1726 | /* Slot must be unusable until thread is really gone */ | ||
1727 | UNLOCK_THREAD_AT_TASK_SWITCH(current); | ||
1728 | switch_thread(); | ||
1729 | /* This should never and must never be reached - if it is, the | ||
1730 | * state is corrupted */ | ||
1731 | THREAD_PANICF("thread_exit->K:*R", current); | ||
1732 | } | 1750 | } |
1733 | 1751 | ||
1734 | #ifdef ALLOW_REMOVE_THREAD | 1752 | #ifdef ALLOW_REMOVE_THREAD |