summaryrefslogtreecommitdiff
path: root/firmware/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/thread.c')
-rw-r--r--firmware/thread.c72
1 files changed, 45 insertions, 27 deletions
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)
156static inline void load_context(const void* addr) 156static inline void load_context(const void* addr)
157 __attribute__((always_inline)); 157 __attribute__((always_inline));
158 158
159#if NUM_CORES > 1
160static void __attribute__((noinline, noreturn))
161 thread_final_exit(struct thread_entry *current);
162#else
163static void __attribute__((always_inline, noreturn))
164 thread_final_exit(struct thread_entry *current);
165#endif
166
159void switch_thread(void) 167void 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 */
857static void check_for_obj_waiters(const char *function, struct thread_entry *thread) 865static 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. */
1678static 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(&current->queue);
1697 corelock_unlock(&current->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
1666void thread_exit(void) 1705void 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(&current->queue);
1725 corelock_unlock(&current->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