summaryrefslogtreecommitdiff
path: root/firmware/kernel/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/kernel/thread.c')
-rw-r--r--firmware/kernel/thread.c400
1 files changed, 26 insertions, 374 deletions
diff --git a/firmware/kernel/thread.c b/firmware/kernel/thread.c
index 9855cc3c84..5bb6eb5522 100644
--- a/firmware/kernel/thread.c
+++ b/firmware/kernel/thread.c
@@ -28,11 +28,7 @@
28#undef _FORTIFY_SOURCE 28#undef _FORTIFY_SOURCE
29#endif 29#endif
30 30
31#include <stdbool.h> 31#include "thread-internal.h"
32#include <stdio.h>
33#include "thread.h"
34#include "panic.h"
35#include "system.h"
36#include "kernel.h" 32#include "kernel.h"
37#include "cpu.h" 33#include "cpu.h"
38#include "string.h" 34#include "string.h"
@@ -40,8 +36,6 @@
40#include <profile.h> 36#include <profile.h>
41#endif 37#endif
42#include "core_alloc.h" 38#include "core_alloc.h"
43#include "gcc_extensions.h"
44#include "corelock.h"
45 39
46/**************************************************************************** 40/****************************************************************************
47 * ATTENTION!! * 41 * ATTENTION!! *
@@ -131,7 +125,6 @@
131 125
132/* Cast to the the machine pointer size, whose size could be < 4 or > 32 126/* Cast to the the machine pointer size, whose size could be < 4 or > 32
133 * (someday :). */ 127 * (someday :). */
134#define DEADBEEF ((uintptr_t)0xdeadbeefdeadbeefull)
135static struct core_entry cores[NUM_CORES] IBSS_ATTR; 128static struct core_entry cores[NUM_CORES] IBSS_ATTR;
136struct thread_entry threads[MAXTHREADS] IBSS_ATTR; 129struct thread_entry threads[MAXTHREADS] IBSS_ATTR;
137 130
@@ -204,57 +197,36 @@ void switch_thread(void)
204 * End Processor-specific section 197 * End Processor-specific section
205 ***************************************************************************/ 198 ***************************************************************************/
206 199
207#if THREAD_EXTRA_CHECKS 200static NO_INLINE
208static void thread_panicf(const char *msg, struct thread_entry *thread) 201 void thread_panicf(const char *msg, struct thread_entry *thread)
209{ 202{
210 IF_COP( const unsigned int core = thread->core; ) 203 IF_COP( const unsigned int core = thread->core; )
211 static char name[32]; 204 static char namebuf[sizeof (((struct thread_debug_info *)0)->name)];
212 thread_get_name(name, 32, thread); 205 const char *name = thread->name;
206 if (!name)
207 name = "";
208 snprintf(namebuf, sizeof (namebuf), *name ? "%s" : "%s%08lX",
209 name, (unsigned long)thread->id);
213 panicf ("%s %s" IF_COP(" (%d)"), msg, name IF_COP(, core)); 210 panicf ("%s %s" IF_COP(" (%d)"), msg, name IF_COP(, core));
214} 211}
212
215static void thread_stkov(struct thread_entry *thread) 213static void thread_stkov(struct thread_entry *thread)
216{ 214{
217 thread_panicf("Stkov", thread); 215 thread_panicf("Stkov", thread);
218} 216}
217
218#if THREAD_EXTRA_CHECKS
219#define THREAD_PANICF(msg, thread) \ 219#define THREAD_PANICF(msg, thread) \
220 thread_panicf(msg, thread) 220 thread_panicf(msg, thread)
221#define THREAD_ASSERT(exp, msg, thread) \ 221#define THREAD_ASSERT(exp, msg, thread) \
222 ({ if (!({ exp; })) thread_panicf((msg), (thread)); }) 222 ({ if (!({ exp; })) thread_panicf((msg), (thread)); })
223#else 223#else
224static void thread_stkov(struct thread_entry *thread) 224#define THREAD_PANICF(msg, thread) \
225{ 225 do {} while (0)
226 IF_COP( const unsigned int core = thread->core; ) 226#define THREAD_ASSERT(exp, msg, thread) \
227 static char name[32]; 227 do {} while (0)
228 thread_get_name(name, 32, thread);
229 panicf("Stkov %s" IF_COP(" (%d)"), name IF_COP(, core));
230}
231#define THREAD_PANICF(msg, thread)
232#define THREAD_ASSERT(exp, msg, thread)
233#endif /* THREAD_EXTRA_CHECKS */ 228#endif /* THREAD_EXTRA_CHECKS */
234 229
235/* Thread locking */
236#if NUM_CORES > 1
237#define LOCK_THREAD(thread) \
238 ({ corelock_lock(&(thread)->slot_cl); })
239#define TRY_LOCK_THREAD(thread) \
240 ({ corelock_try_lock(&(thread)->slot_cl); })
241#define UNLOCK_THREAD(thread) \
242 ({ corelock_unlock(&(thread)->slot_cl); })
243#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
244 ({ unsigned int _core = (thread)->core; \
245 cores[_core].blk_ops.flags |= TBOP_UNLOCK_CORELOCK; \
246 cores[_core].blk_ops.cl_p = &(thread)->slot_cl; })
247#else
248#define LOCK_THREAD(thread) \
249 ({ (void)(thread); })
250#define TRY_LOCK_THREAD(thread) \
251 ({ (void)(thread); })
252#define UNLOCK_THREAD(thread) \
253 ({ (void)(thread); })
254#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
255 ({ (void)(thread); })
256#endif
257
258/* RTR list */ 230/* RTR list */
259#define RTR_LOCK(core) \ 231#define RTR_LOCK(core) \
260 ({ corelock_lock(&cores[core].rtr_cl); }) 232 ({ corelock_lock(&cores[core].rtr_cl); })
@@ -993,27 +965,6 @@ static void wakeup_thread_release(struct thread_entry *thread)
993 inherit_priority(bl, bl, blt, newblpr); 965 inherit_priority(bl, bl, blt, newblpr);
994} 966}
995 967
996/*---------------------------------------------------------------------------
997 * No threads must be blocked waiting for this thread except for it to exit.
998 * The alternative is more elaborate cleanup and object registration code.
999 * Check this for risk of silent data corruption when objects with
1000 * inheritable blocking are abandoned by the owner - not precise but may
1001 * catch something.
1002 *---------------------------------------------------------------------------
1003 */
1004static void __attribute__((noinline)) check_for_obj_waiters(
1005 const char *function, struct thread_entry *thread)
1006{
1007 /* Only one bit in the mask should be set with a frequency on 1 which
1008 * represents the thread's own base priority */
1009 if (priobit_popcount(&thread->pdist.mask) != 1 ||
1010 thread->pdist.hist[priobit_ffs(&thread->pdist.mask)] > 1)
1011 {
1012 unsigned char name[32];
1013 thread_get_name(name, 32, thread);
1014 panicf("%s->%s with obj. waiters", function, name);
1015 }
1016}
1017#endif /* HAVE_PRIORITY_SCHEDULING */ 968#endif /* HAVE_PRIORITY_SCHEDULING */
1018 969
1019/*--------------------------------------------------------------------------- 970/*---------------------------------------------------------------------------
@@ -1520,31 +1471,6 @@ void block_thread(struct thread_entry *current, int timeout)
1520} 1471}
1521 1472
1522/*--------------------------------------------------------------------------- 1473/*---------------------------------------------------------------------------
1523 * Wakeup an entire queue of threads - returns bitwise-or of return bitmask
1524 * from each operation or THREAD_NONE of nothing was awakened. Object owning
1525 * the queue must be locked first.
1526 *
1527 * INTERNAL: Intended for use by kernel objects and not for programs.
1528 *---------------------------------------------------------------------------
1529 */
1530unsigned int thread_queue_wake(struct thread_entry **list)
1531{
1532 unsigned result = THREAD_NONE;
1533
1534 for (;;)
1535 {
1536 unsigned int rc = wakeup_thread(list, WAKEUP_DEFAULT);
1537
1538 if (rc == THREAD_NONE)
1539 break; /* No more threads */
1540
1541 result |= rc;
1542 }
1543
1544 return result;
1545}
1546
1547/*---------------------------------------------------------------------------
1548 * Assign the thread slot a new ID. Version is 0x00000100..0xffffff00. 1474 * Assign the thread slot a new ID. Version is 0x00000100..0xffffff00.
1549 *--------------------------------------------------------------------------- 1475 *---------------------------------------------------------------------------
1550 */ 1476 */
@@ -1580,7 +1506,7 @@ static struct thread_entry * find_empty_thread_slot(void)
1580 struct thread_entry *t = &threads[n]; 1506 struct thread_entry *t = &threads[n];
1581 LOCK_THREAD(t); 1507 LOCK_THREAD(t);
1582 1508
1583 if (t->state == STATE_KILLED IF_COP( && t->name != THREAD_DESTRUCT )) 1509 if (t->state == STATE_KILLED)
1584 { 1510 {
1585 /* Slot is empty - leave it locked and caller will unlock */ 1511 /* Slot is empty - leave it locked and caller will unlock */
1586 thread = t; 1512 thread = t;
@@ -1836,21 +1762,14 @@ void thread_exit(void)
1836 corelock_lock(&current->waiter_cl); 1762 corelock_lock(&current->waiter_cl);
1837 LOCK_THREAD(current); 1763 LOCK_THREAD(current);
1838 1764
1839#if defined (ALLOW_REMOVE_THREAD) && NUM_CORES > 1
1840 if (current->name == THREAD_DESTRUCT)
1841 {
1842 /* Thread being killed - become a waiter */
1843 unsigned int id = current->id;
1844 UNLOCK_THREAD(current);
1845 corelock_unlock(&current->waiter_cl);
1846 thread_wait(id);
1847 THREAD_PANICF("thread_exit->WK:*R", current);
1848 }
1849#endif
1850
1851#ifdef HAVE_PRIORITY_SCHEDULING 1765#ifdef HAVE_PRIORITY_SCHEDULING
1852 check_for_obj_waiters("thread_exit", current); 1766 /* Only one bit in the mask should be set with a frequency on 1 which
1853#endif 1767 * represents the thread's own base priority otherwise threads are waiting
1768 * on an abandoned object */
1769 if (priobit_popcount(&current->pdist.mask) != 1 ||
1770 current->pdist.hist[priobit_ffs(&current->pdist.mask)] > 1)
1771 thread_panicf("abandon ship!", current);
1772#endif /* HAVE_PRIORITY_SCHEDULING */
1854 1773
1855 if (current->tmo.prev != NULL) 1774 if (current->tmo.prev != NULL)
1856 { 1775 {
@@ -1872,186 +1791,6 @@ void thread_exit(void)
1872 thread_final_exit(current); 1791 thread_final_exit(current);
1873} 1792}
1874 1793
1875#ifdef ALLOW_REMOVE_THREAD
1876/*---------------------------------------------------------------------------
1877 * Remove a thread from the scheduler. Not The Right Way to Do Things in
1878 * normal programs.
1879 *
1880 * Parameter is the ID as returned from create_thread().
1881 *
1882 * Use with care on threads that are not under careful control as this may
1883 * leave various objects in an undefined state.
1884 *---------------------------------------------------------------------------
1885 */
1886void remove_thread(unsigned int thread_id)
1887{
1888#ifdef HAVE_CORELOCK_OBJECT
1889 /* core is not constant here because of core switching */
1890 unsigned int core = CURRENT_CORE;
1891 unsigned int old_core = NUM_CORES;
1892 struct corelock *ocl = NULL;
1893#else
1894 const unsigned int core = CURRENT_CORE;
1895#endif
1896 struct thread_entry *current = cores[core].running;
1897 struct thread_entry *thread = thread_id_entry(thread_id);
1898
1899 unsigned state;
1900 int oldlevel;
1901
1902 if (thread == current)
1903 thread_exit(); /* Current thread - do normal exit */
1904
1905 oldlevel = disable_irq_save();
1906
1907 corelock_lock(&thread->waiter_cl);
1908 LOCK_THREAD(thread);
1909
1910 state = thread->state;
1911
1912 if (thread->id != thread_id || state == STATE_KILLED)
1913 goto thread_killed;
1914
1915#if NUM_CORES > 1
1916 if (thread->name == THREAD_DESTRUCT)
1917 {
1918 /* Thread being killed - become a waiter */
1919 UNLOCK_THREAD(thread);
1920 corelock_unlock(&thread->waiter_cl);
1921 restore_irq(oldlevel);
1922 thread_wait(thread_id);
1923 return;
1924 }
1925
1926 thread->name = THREAD_DESTRUCT; /* Slot can't be used for now */
1927
1928#ifdef HAVE_PRIORITY_SCHEDULING
1929 check_for_obj_waiters("remove_thread", thread);
1930#endif
1931
1932 if (thread->core != core)
1933 {
1934 /* Switch cores and safely extract the thread there */
1935 /* Slot HAS to be unlocked or a deadlock could occur which means other
1936 * threads have to be guided into becoming thread waiters if they
1937 * attempt to remove it. */
1938 unsigned int new_core = thread->core;
1939
1940 corelock_unlock(&thread->waiter_cl);
1941
1942 UNLOCK_THREAD(thread);
1943 restore_irq(oldlevel);
1944
1945 old_core = switch_core(new_core);
1946
1947 oldlevel = disable_irq_save();
1948
1949 corelock_lock(&thread->waiter_cl);
1950 LOCK_THREAD(thread);
1951
1952 state = thread->state;
1953 core = new_core;
1954 /* Perform the extraction and switch ourselves back to the original
1955 processor */
1956 }
1957#endif /* NUM_CORES > 1 */
1958
1959 if (thread->tmo.prev != NULL)
1960 {
1961 /* Clean thread off the timeout list if a timeout check hasn't
1962 * run yet */
1963 remove_from_list_tmo(thread);
1964 }
1965
1966#ifdef HAVE_SCHEDULER_BOOSTCTRL
1967 /* Cancel CPU boost if any */
1968 boost_thread(thread, false);
1969#endif
1970
1971IF_COP( retry_state: )
1972
1973 switch (state)
1974 {
1975 case STATE_RUNNING:
1976 RTR_LOCK(core);
1977 /* Remove thread from ready to run tasks */
1978 remove_from_list_l(&cores[core].running, thread);
1979 rtr_subtract_entry(core, thread->priority);
1980 RTR_UNLOCK(core);
1981 break;
1982 case STATE_BLOCKED:
1983 case STATE_BLOCKED_W_TMO:
1984 /* Remove thread from the queue it's blocked on - including its
1985 * own if waiting there */
1986#if NUM_CORES > 1
1987 if (&thread->waiter_cl != thread->obj_cl)
1988 {
1989 ocl = thread->obj_cl;
1990
1991 if (UNLIKELY(corelock_try_lock(ocl) == 0))
1992 {
1993 UNLOCK_THREAD(thread);
1994 corelock_lock(ocl);
1995 LOCK_THREAD(thread);
1996
1997 if (UNLIKELY(thread->state != state))
1998 {
1999 /* Something woke the thread */
2000 state = thread->state;
2001 corelock_unlock(ocl);
2002 goto retry_state;
2003 }
2004 }
2005 }
2006#endif
2007#ifdef HAVE_WAKEUP_EXT_CB
2008 if (thread->wakeup_ext_cb != NULL)
2009 thread->wakeup_ext_cb(thread);
2010#endif
2011
2012#ifdef HAVE_PRIORITY_SCHEDULING
2013 /* Remove thread's priority influence from its chain if needed */
2014 if (thread->blocker != NULL)
2015 wakeup_priority_protocol_release(thread);
2016 else
2017#endif
2018 remove_from_list_l(thread->bqp, thread);
2019
2020#if NUM_CORES > 1
2021 if (ocl != NULL)
2022 corelock_unlock(ocl);
2023#endif
2024 break;
2025 /* Otherwise thread is frozen and hasn't run yet */
2026 }
2027
2028 new_thread_id(thread_id, thread);
2029 thread->state = STATE_KILLED;
2030
2031 /* If thread was waiting on itself, it will have been removed above.
2032 * The wrong order would result in waking the thread first and deadlocking
2033 * since the slot is already locked. */
2034 thread_queue_wake(&thread->queue);
2035
2036 thread->name = NULL;
2037
2038thread_killed: /* Thread was already killed */
2039 /* Removal complete - safe to unlock and reenable interrupts */
2040 corelock_unlock(&thread->waiter_cl);
2041 UNLOCK_THREAD(thread);
2042 restore_irq(oldlevel);
2043
2044#if NUM_CORES > 1
2045 if (old_core < NUM_CORES)
2046 {
2047 /* Did a removal on another processor's thread - switch back to
2048 native core */
2049 switch_core(old_core);
2050 }
2051#endif
2052}
2053#endif /* ALLOW_REMOVE_THREAD */
2054
2055#ifdef HAVE_PRIORITY_SCHEDULING 1794#ifdef HAVE_PRIORITY_SCHEDULING
2056/*--------------------------------------------------------------------------- 1795/*---------------------------------------------------------------------------
2057 * Sets the thread's relative base priority for the core it runs on. Any 1796 * Sets the thread's relative base priority for the core it runs on. Any
@@ -2205,20 +1944,9 @@ unsigned int switch_core(unsigned int new_core)
2205 return core; 1944 return core;
2206 } 1945 }
2207 1946
2208 int oldlevel = disable_irq_save(); 1947 disable_irq();
2209 LOCK_THREAD(current); 1948 LOCK_THREAD(current);
2210 1949
2211 if (current->name == THREAD_DESTRUCT)
2212 {
2213 /* Thread being killed - deactivate and let process complete */
2214 unsigned int id = current->id;
2215 UNLOCK_THREAD(current);
2216 restore_irq(oldlevel);
2217 thread_wait(id);
2218 /* Should never be reached */
2219 THREAD_PANICF("switch_core->D:*R", current);
2220 }
2221
2222 /* Get us off the running list for the current core */ 1950 /* Get us off the running list for the current core */
2223 RTR_LOCK(core); 1951 RTR_LOCK(core);
2224 remove_from_list_l(&cores[core].running, current); 1952 remove_from_list_l(&cores[core].running, current);
@@ -2274,7 +2002,7 @@ unsigned int switch_core(unsigned int new_core)
2274 * are safe to perform. 2002 * are safe to perform.
2275 *--------------------------------------------------------------------------- 2003 *---------------------------------------------------------------------------
2276 */ 2004 */
2277void init_threads(void) 2005void INIT_ATTR init_threads(void)
2278{ 2006{
2279 const unsigned int core = CURRENT_CORE; 2007 const unsigned int core = CURRENT_CORE;
2280 struct thread_entry *thread; 2008 struct thread_entry *thread;
@@ -2353,82 +2081,6 @@ void init_threads(void)
2353#endif 2081#endif
2354} 2082}
2355 2083
2356/* Shared stack scan helper for thread_stack_usage and idle_stack_usage */
2357#if NUM_CORES == 1
2358static inline int stack_usage(uintptr_t *stackptr, size_t stack_size)
2359#else
2360static int stack_usage(uintptr_t *stackptr, size_t stack_size)
2361#endif
2362{
2363 unsigned int stack_words = stack_size / sizeof (uintptr_t);
2364 unsigned int i;
2365 int usage = 0;
2366
2367 for (i = 0; i < stack_words; i++)
2368 {
2369 if (stackptr[i] != DEADBEEF)
2370 {
2371 usage = ((stack_words - i) * 100) / stack_words;
2372 break;
2373 }
2374 }
2375
2376 return usage;
2377}
2378
2379/*---------------------------------------------------------------------------
2380 * Returns the maximum percentage of stack a thread ever used while running.
2381 * NOTE: Some large buffer allocations that don't use enough the buffer to
2382 * overwrite stackptr[0] will not be seen.
2383 *---------------------------------------------------------------------------
2384 */
2385int thread_stack_usage(const struct thread_entry *thread)
2386{
2387 if (LIKELY(thread->stack_size > 0))
2388 return stack_usage(thread->stack, thread->stack_size);
2389 return 0;
2390}
2391
2392#if NUM_CORES > 1
2393/*---------------------------------------------------------------------------
2394 * Returns the maximum percentage of the core's idle stack ever used during
2395 * runtime.
2396 *---------------------------------------------------------------------------
2397 */
2398int idle_stack_usage(unsigned int core)
2399{
2400 return stack_usage(idle_stacks[core], IDLE_STACK_SIZE);
2401}
2402#endif
2403
2404/*---------------------------------------------------------------------------
2405 * Fills in the buffer with the specified thread's name. If the name is NULL,
2406 * empty, or the thread is in destruct state a formatted ID is written
2407 * instead.
2408 *---------------------------------------------------------------------------
2409 */
2410void thread_get_name(char *buffer, int size,
2411 struct thread_entry *thread)
2412{
2413 if (size <= 0)
2414 return;
2415
2416 *buffer = '\0';
2417
2418 if (thread)
2419 {
2420 /* Display thread name if one or ID if none */
2421 const char *name = thread->name;
2422 const char *fmt = "%s";
2423 if (name == NULL IF_COP(|| name == THREAD_DESTRUCT) || *name == '\0')
2424 {
2425 name = (const char *)(uintptr_t)thread->id;
2426 fmt = "%04lX";
2427 }
2428 snprintf(buffer, size, fmt, name);
2429 }
2430}
2431
2432/* Unless otherwise defined, do nothing */ 2084/* Unless otherwise defined, do nothing */
2433#ifndef YIELD_KERNEL_HOOK 2085#ifndef YIELD_KERNEL_HOOK
2434#define YIELD_KERNEL_HOOK() false 2086#define YIELD_KERNEL_HOOK() false