summaryrefslogtreecommitdiffstats
path: root/firmware/kernel
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2014-08-08 01:39:29 -0400
committerMichael Sevakis <jethead71@rockbox.org>2014-08-08 01:59:59 -0400
commit981d028c09d10ed867f2f955f58d60b753c64f29 (patch)
tree0dab835a14c5cb3e740be4e46be93c42aec76bc5 /firmware/kernel
parent53d9f2e6a7564e487bdac87f6e28c662e8407458 (diff)
downloadrockbox-981d028c09d10ed867f2f955f58d60b753c64f29.tar.gz
rockbox-981d028c09d10ed867f2f955f58d60b753c64f29.tar.bz2
rockbox-981d028c09d10ed867f2f955f58d60b753c64f29.zip
Do some kernel cleanup
* Seal away private thread and kernel definitions and declarations into the internal headers in order to better hide internal structure. * Add a thread-common.c file that keeps shared functions together. List functions aren't messed with since that's about to be changed to different ones. * It is necessary to modify some ARM/PP stuff since GCC was complaining about constant pool distance and I would rather not force dump it. Just bl the cache calls in the startup and exit code and let it use veneers if it must. * Clean up redundant #includes in relevant areas and reorganize them. * Expunge useless and dangerous stuff like remove_thread(). Change-Id: I6e22932fad61a9fac30fd1363c071074ee7ab382
Diffstat (limited to 'firmware/kernel')
-rw-r--r--firmware/kernel/include/corelock.h12
-rw-r--r--firmware/kernel/include/kernel.h19
-rw-r--r--firmware/kernel/include/mrsw_lock.h2
-rw-r--r--firmware/kernel/include/mutex.h2
-rw-r--r--firmware/kernel/include/semaphore.h1
-rw-r--r--firmware/kernel/include/thread.h279
-rw-r--r--firmware/kernel/kernel-internal.h22
-rw-r--r--firmware/kernel/mrsw_lock.c8
-rw-r--r--firmware/kernel/mutex.c7
-rw-r--r--firmware/kernel/pthread/thread.c17
-rw-r--r--firmware/kernel/queue.c8
-rw-r--r--firmware/kernel/semaphore.c12
-rw-r--r--firmware/kernel/thread-common.c152
-rw-r--r--firmware/kernel/thread-internal.h237
-rw-r--r--firmware/kernel/thread.c400
15 files changed, 333 insertions, 845 deletions
diff --git a/firmware/kernel/include/corelock.h b/firmware/kernel/include/corelock.h
index 79302e0e3c..402ae07d19 100644
--- a/firmware/kernel/include/corelock.h
+++ b/firmware/kernel/include/corelock.h
@@ -28,10 +28,14 @@
#ifndef HAVE_CORELOCK_OBJECT
/* No atomic corelock op needed or just none defined */
-#define corelock_init(cl)
-#define corelock_lock(cl)
-#define corelock_try_lock(cl)
-#define corelock_unlock(cl)
+#define corelock_init(cl) \
+ do {} while (0)
+#define corelock_lock(cl) \
+ do {} while (0)
+#define corelock_try_lock(cl) \
+ do {} while (0)
+#define corelock_unlock(cl) \
+ do {} while (0)
#else
diff --git a/firmware/kernel/include/kernel.h b/firmware/kernel/include/kernel.h
index d2ffffcda9..fc6dfca8c3 100644
--- a/firmware/kernel/include/kernel.h
+++ b/firmware/kernel/include/kernel.h
@@ -48,23 +48,4 @@
#define TIMEOUT_BLOCK -1
#define TIMEOUT_NOBLOCK 0
-static inline void kernel_init(void)
-{
- /* Init the threading API */
- init_threads();
-
- /* Other processors will not reach this point in a multicore build.
- * In a single-core build with multiple cores they fall-through and
- * sleep in cop_main without returning. */
- if (CURRENT_CORE == CPU)
- {
- init_queues();
- init_tick();
-#ifdef KDEV_INIT
- kernel_device_init();
-#endif
- }
-}
-
-
#endif /* KERNEL_H */
diff --git a/firmware/kernel/include/mrsw_lock.h b/firmware/kernel/include/mrsw_lock.h
index fbfe1d405d..d919f7be26 100644
--- a/firmware/kernel/include/mrsw_lock.h
+++ b/firmware/kernel/include/mrsw_lock.h
@@ -21,6 +21,8 @@
#ifndef MRSW_LOCK_H
#define MRSW_LOCK_H
+#include "thread.h"
+
/* Multi-reader, single-writer object that allows mutltiple readers or a
* single writer thread access to a critical section.
*
diff --git a/firmware/kernel/include/mutex.h b/firmware/kernel/include/mutex.h
index 02b85f331f..72736ec8fd 100644
--- a/firmware/kernel/include/mutex.h
+++ b/firmware/kernel/include/mutex.h
@@ -22,8 +22,6 @@
#ifndef MUTEX_H
#define MUTEX_H
-#include <stdbool.h>
-#include "config.h"
#include "thread.h"
struct mutex
diff --git a/firmware/kernel/include/semaphore.h b/firmware/kernel/include/semaphore.h
index 40e60bb88d..16095d9c2d 100644
--- a/firmware/kernel/include/semaphore.h
+++ b/firmware/kernel/include/semaphore.h
@@ -22,7 +22,6 @@
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
-#include "config.h"
#include "thread.h"
struct semaphore
diff --git a/firmware/kernel/include/thread.h b/firmware/kernel/include/thread.h
index e10b4e21b4..5a8bff0107 100644
--- a/firmware/kernel/include/thread.h
+++ b/firmware/kernel/include/thread.h
@@ -18,17 +18,16 @@
* KIND, either express or implied.
*
****************************************************************************/
-
#ifndef THREAD_H
#define THREAD_H
-#include "config.h"
#include <inttypes.h>
#include <stddef.h>
#include <stdbool.h>
+#include "config.h"
#include "gcc_extensions.h"
-#include "corelock.h"
#include "bitarray.h"
+#include "corelock.h"
/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works
* by giving high priority threads more CPU time than lower priority threads
@@ -65,7 +64,6 @@
#define IO_PRIORITY_IMMEDIATE 0
#define IO_PRIORITY_BACKGROUND 32
-
#if CONFIG_CODEC == SWCODEC
# ifdef HAVE_HARDWARE_CLICK
# define BASETHREADS 17
@@ -85,6 +83,8 @@
BITARRAY_TYPE_DECLARE(threadbit_t, threadbit, MAXTHREADS)
BITARRAY_TYPE_DECLARE(priobit_t, priobit, NUM_PRIORITIES)
+struct thread_entry;
+
/*
* We need more stack when we run under a host
* maybe more expensive C lib functions?
@@ -92,53 +92,22 @@ BITARRAY_TYPE_DECLARE(priobit_t, priobit, NUM_PRIORITIES)
* simulator (possibly) doesn't simulate stack usage anyway but well ... */
#if defined(HAVE_SDL_THREADS) || defined(__PCTOOL__)
-struct regs
-{
- void *t; /* OS thread */
- void *told; /* Last thread in slot (explained in thead-sdl.c) */
- void *s; /* Semaphore for blocking and wakeup */
- void (*start)(void); /* Start function */
-};
-
#define DEFAULT_STACK_SIZE 0x100 /* tiny, ignored anyway */
#else
#include "asm/thread.h"
#endif /* HAVE_SDL_THREADS */
-/* NOTE: The use of the word "queue" may also refer to a linked list of
- threads being maintained that are normally dealt with in FIFO order
- and not necessarily kernel event_queue */
-enum
-{
- /* States without a timeout must be first */
- STATE_KILLED = 0, /* Thread is killed (default) */
- STATE_RUNNING, /* Thread is currently running */
- STATE_BLOCKED, /* Thread is indefinitely blocked on a queue */
- /* These states involve adding the thread to the tmo list */
- STATE_SLEEPING, /* Thread is sleeping with a timeout */
- STATE_BLOCKED_W_TMO, /* Thread is blocked on a queue with a timeout */
- /* Miscellaneous states */
- STATE_FROZEN, /* Thread is suspended and will not run until
- thread_thaw is called with its ID */
- THREAD_NUM_STATES,
- TIMEOUT_STATE_FIRST = STATE_SLEEPING,
-};
+extern void yield(void);
+extern unsigned sleep(unsigned ticks);
-#if NUM_CORES > 1
-/* Pointer value for name field to indicate thread is being killed. Using
- * an alternate STATE_* won't work since that would interfere with operation
- * while the thread is still running. */
-#define THREAD_DESTRUCT ((const char *)~(intptr_t)0)
+#ifdef HAVE_PRIORITY_SCHEDULING
+#define IF_PRIO(...) __VA_ARGS__
+#define IFN_PRIO(...)
+#else
+#define IF_PRIO(...)
+#define IFN_PRIO(...) __VA_ARGS__
#endif
-/* Link information for lists thread is in */
-struct thread_entry; /* forward */
-struct thread_list
-{
- struct thread_entry *prev; /* Previous thread in a list */
- struct thread_entry *next; /* Next thread in a list */
-};
-
/* Basic structure describing the owner of an object */
struct blocker
{
@@ -163,157 +132,9 @@ struct blocker_splay
#endif /* HAVE_PRIORITY_SCHEDULING */
};
-#ifdef HAVE_PRIORITY_SCHEDULING
-
-/* Quick-disinherit of priority elevation. Must be a running thread. */
-void priority_disinherit(struct thread_entry *thread, struct blocker *bl);
-
-struct priority_distribution
-{
- uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */
- priobit_t mask; /* Bitmask of hist entries that are not zero */
-};
-
-#endif /* HAVE_PRIORITY_SCHEDULING */
-
-/* Information kept in each thread slot
- * members are arranged according to size - largest first - in order
- * to ensure both alignment and packing at the same time.
- */
-struct thread_entry
-{
- struct regs context; /* Register context at switch -
- _must_ be first member */
- uintptr_t *stack; /* Pointer to top of stack */
- const char *name; /* Thread name */
- long tmo_tick; /* Tick when thread should be woken from
- timeout -
- states: STATE_SLEEPING/STATE_BLOCKED_W_TMO */
- struct thread_list l; /* Links for blocked/waking/running -
- circular linkage in both directions */
- struct thread_list tmo; /* Links for timeout list -
- Circular in reverse direction, NULL-terminated in
- forward direction -
- states: STATE_SLEEPING/STATE_BLOCKED_W_TMO */
- struct thread_entry **bqp; /* Pointer to list variable in kernel
- object where thread is blocked - used
- for implicit unblock and explicit wake
- states: STATE_BLOCKED/STATE_BLOCKED_W_TMO */
-#ifdef HAVE_CORELOCK_OBJECT
- struct corelock *obj_cl; /* Object corelock where thead is blocked -
- states: STATE_BLOCKED/STATE_BLOCKED_W_TMO */
- struct corelock waiter_cl; /* Corelock for thread_wait */
- struct corelock slot_cl; /* Corelock to lock thread slot */
- unsigned char core; /* The core to which thread belongs */
-#endif
- struct thread_entry *queue; /* List of threads waiting for thread to be
- removed */
-#ifdef HAVE_WAKEUP_EXT_CB
- void (*wakeup_ext_cb)(struct thread_entry *thread); /* Callback that
- performs special steps needed when being
- forced off of an object's wait queue that
- go beyond the standard wait queue removal
- and priority disinheritance */
- /* Only enabled when using queue_send for now */
-#endif
-#if defined(HAVE_SEMAPHORE_OBJECTS) || \
- defined(HAVE_EXTENDED_MESSAGING_AND_NAME) || \
- NUM_CORES > 1
- volatile intptr_t retval; /* Return value from a blocked operation/
- misc. use */
-#endif
- uint32_t id; /* Current slot id */
- int __errno; /* Thread error number (errno tls) */
-#ifdef HAVE_PRIORITY_SCHEDULING
- /* Priority summary of owned objects that support inheritance */
- struct blocker *blocker; /* Pointer to blocker when this thread is blocked
- on an object that supports PIP -
- states: STATE_BLOCKED/STATE_BLOCKED_W_TMO */
- struct priority_distribution pdist; /* Priority summary of owned objects
- that have blocked threads and thread's own
- base priority */
- int skip_count; /* Number of times skipped if higher priority
- thread was running */
- unsigned char base_priority; /* Base priority (set explicitly during
- creation or thread_set_priority) */
- unsigned char priority; /* Scheduled priority (higher of base or
- all threads blocked by this one) */
-#endif
- unsigned short stack_size; /* Size of stack in bytes */
- unsigned char state; /* Thread slot state (STATE_*) */
-#ifdef HAVE_SCHEDULER_BOOSTCTRL
- unsigned char cpu_boost; /* CPU frequency boost flag */
-#endif
-#ifdef HAVE_IO_PRIORITY
- unsigned char io_priority;
-#endif
-};
-
-/*** Macros for internal use ***/
-/* Thread ID, 32 bits = |VVVVVVVV|VVVVVVVV|VVVVVVVV|SSSSSSSS| */
-#define THREAD_ID_VERSION_SHIFT 8
-#define THREAD_ID_VERSION_MASK 0xffffff00
-#define THREAD_ID_SLOT_MASK 0x000000ff
-#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n))
-#define THREAD_ID_SLOT(id) ((id) & THREAD_ID_SLOT_MASK)
-
-#ifdef HAVE_CORELOCK_OBJECT
-/* Operations to be performed just before stopping a thread and starting
- a new one if specified before calling switch_thread */
-enum
-{
- TBOP_CLEAR = 0, /* No operation to do */
- TBOP_UNLOCK_CORELOCK, /* Unlock a corelock variable */
- TBOP_SWITCH_CORE, /* Call the core switch preparation routine */
-};
-
-struct thread_blk_ops
-{
- struct corelock *cl_p; /* pointer to corelock */
- unsigned char flags; /* TBOP_* flags */
-};
-#endif /* NUM_CORES > 1 */
-
-/* Information kept for each core
- * Members are arranged for the same reason as in thread_entry
- */
-struct core_entry
-{
- /* "Active" lists - core is constantly active on these and are never
- locked and interrupts do not access them */
- struct thread_entry *running; /* threads that are running (RTR) */
- struct thread_entry *timeout; /* threads that are on a timeout before
- running again */
- struct thread_entry *block_task; /* Task going off running list */
-#ifdef HAVE_PRIORITY_SCHEDULING
- struct priority_distribution rtr; /* Summary of running and ready-to-run
- threads */
-#endif
- long next_tmo_check; /* soonest time to check tmo threads */
-#ifdef HAVE_CORELOCK_OBJECT
- struct thread_blk_ops blk_ops; /* operations to perform when
- blocking a thread */
- struct corelock rtr_cl; /* Lock for rtr list */
-#endif /* NUM_CORES */
-};
-
-extern void yield(void);
-extern unsigned sleep(unsigned ticks);
-
-#ifdef HAVE_PRIORITY_SCHEDULING
-#define IF_PRIO(...) __VA_ARGS__
-#define IFN_PRIO(...)
-#else
-#define IF_PRIO(...)
-#define IFN_PRIO(...) __VA_ARGS__
-#endif
-
void core_idle(void);
void core_wake(IF_COP_VOID(unsigned int core));
-/* Initialize the scheduler */
-void init_threads(void) INIT_ATTR;
-
/* Allocate a thread in the scheduler */
#define CREATE_THREAD_FROZEN 0x00000001 /* Thread is frozen at create time */
unsigned int create_thread(void (*function)(void),
@@ -330,59 +151,17 @@ void cancel_cpu_boost(void);
#define trigger_cpu_boost() do { } while(0)
#define cancel_cpu_boost() do { } while(0)
#endif
-/* Return thread entry from id */
-struct thread_entry *thread_id_entry(unsigned int thread_id);
-/* Make a frozed thread runnable (when started with CREATE_THREAD_FROZEN).
+/* Make a frozen thread runnable (when started with CREATE_THREAD_FROZEN).
* Has no effect on a thread not frozen. */
void thread_thaw(unsigned int thread_id);
/* Wait for a thread to exit */
void thread_wait(unsigned int thread_id);
/* Exit the current thread */
void thread_exit(void) NORETURN_ATTR;
-#if defined(DEBUG) || defined(ROCKBOX_HAS_LOGF)
-#define ALLOW_REMOVE_THREAD
-/* Remove a thread from the scheduler */
-void remove_thread(unsigned int thread_id);
-#endif
-
-/* Switch to next runnable thread */
-void switch_thread(void);
-/* Blocks a thread for at least the specified number of ticks (0 = wait until
- * next tick) */
-void sleep_thread(int ticks);
-/* Blocks the current thread on a thread queue (< 0 == infinite) */
-void block_thread(struct thread_entry *current, int timeout);
-
-/* Return bit flags for thread wakeup */
-#define THREAD_NONE 0x0 /* No thread woken up (exclusive) */
-#define THREAD_OK 0x1 /* A thread was woken up */
-#define THREAD_SWITCH 0x2 /* Task switch recommended (one or more of
- higher priority than current were woken) */
-
-/* A convenience function for waking an entire queue of threads. */
-unsigned int thread_queue_wake(struct thread_entry **list);
-
-/* Wakeup a thread at the head of a list */
-enum wakeup_thread_protocol
-{
- WAKEUP_DEFAULT,
- WAKEUP_TRANSFER,
- WAKEUP_RELEASE,
- WAKEUP_TRANSFER_MULTI,
-};
-
-unsigned int wakeup_thread_(struct thread_entry **list
- IF_PRIO(, enum wakeup_thread_protocol proto));
#ifdef HAVE_PRIORITY_SCHEDULING
-#define wakeup_thread(list, proto) \
- wakeup_thread_((list), (proto))
-
int thread_set_priority(unsigned int thread_id, int priority);
int thread_get_priority(unsigned int thread_id);
-#else /* !HAVE_PRIORITY_SCHEDULING */
-#define wakeup_thread(list, proto...) \
- wakeup_thread_((list));
#endif /* HAVE_PRIORITY_SCHEDULING */
#ifdef HAVE_IO_PRIORITY
@@ -396,19 +175,31 @@ unsigned int switch_core(unsigned int new_core);
/* Return the id of the calling thread. */
unsigned int thread_self(void);
-/* Return the thread_entry for the calling thread.
- * INTERNAL: Intended for use by kernel and not for programs. */
-struct thread_entry* thread_self_entry(void);
-
/* Debugging info - only! */
-int thread_stack_usage(const struct thread_entry *thread);
#if NUM_CORES > 1
-int idle_stack_usage(unsigned int core);
+struct core_debug_info
+{
+ unsigned int idle_stack_usage;
+};
+
+int core_get_debug_info(unsigned int core, struct core_debug_info *infop);
+
+#endif /* NUM_CORES */
+
+struct thread_debug_info
+{
+ char statusstr[4];
+ char name[32];
+ unsigned int stack_usage;
+#if NUM_CORES > 1
+ unsigned int core;
#endif
-void thread_get_name(char *buffer, int size,
- struct thread_entry *thread);
-#ifdef RB_PROFILE
-void profile_thread(void);
+#ifdef HAVE_PRIORITY_SCHEDULING
+ int base_priority;
+ int current_priority;
#endif
+};
+int thread_get_debug_info(unsigned int thread_id,
+ struct thread_debug_info *infop);
#endif /* THREAD_H */
diff --git a/firmware/kernel/kernel-internal.h b/firmware/kernel/kernel-internal.h
index 51c589ac8f..8f7e3e28cb 100644
--- a/firmware/kernel/kernel-internal.h
+++ b/firmware/kernel/kernel-internal.h
@@ -22,8 +22,8 @@
#ifndef KERNEL_INTERNAL_H
#define KERNEL_INTERNAL_H
-#include "config.h"
-#include "debug.h"
+#include "thread-internal.h"
+#include "kernel.h"
/* Make this nonzero to enable more elaborate checks on objects */
#if defined(DEBUG) || defined(SIMULATOR)
@@ -45,5 +45,23 @@
#define KERNEL_ASSERT(exp, msg...) ({})
#endif
+static inline void kernel_init(void)
+{
+ /* Init the threading API */
+ extern void init_threads(void);
+ init_threads();
+
+ /* Other processors will not reach this point in a multicore build.
+ * In a single-core build with multiple cores they fall-through and
+ * sleep in cop_main without returning. */
+ if (CURRENT_CORE == CPU)
+ {
+ init_queues();
+ init_tick();
+#ifdef KDEV_INIT
+ kernel_device_init();
+#endif
+ }
+}
#endif /* KERNEL_INTERNAL_H */
diff --git a/firmware/kernel/mrsw_lock.c b/firmware/kernel/mrsw_lock.c
index 46ab893622..45c8801b74 100644
--- a/firmware/kernel/mrsw_lock.c
+++ b/firmware/kernel/mrsw_lock.c
@@ -18,12 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
-#include <string.h>
-#include "config.h"
-#include "system.h"
-#include "thread.h"
-#include "kernel.h"
#include "kernel-internal.h"
+#include "mrsw-lock.h"
#ifdef HAVE_PRIORITY_SCHEDULING
@@ -45,9 +41,7 @@ mrsw_reader_relinquish(struct mrsw_lock *mrsw, struct thread_entry *current,
Therefore, if the queue has threads, then the next after the
owning readers is a writer and this is not the last reader. */
if (mrsw->queue)
- {
corelock_lock(&mrsw->splay.cl);
- }
threadbit_clear_bit(&mrsw->splay.mask, slotnum);
diff --git a/firmware/kernel/mutex.c b/firmware/kernel/mutex.c
index 2e90b0f4b1..e5729dc893 100644
--- a/firmware/kernel/mutex.c
+++ b/firmware/kernel/mutex.c
@@ -23,13 +23,8 @@
/****************************************************************************
* Simple mutex functions ;)
****************************************************************************/
-
-#include <stdbool.h>
-#include "config.h"
-#include "system.h"
-#include "kernel.h"
-#include "thread-internal.h"
#include "kernel-internal.h"
+#include "mutex.h"
/* Initialize a mutex object - call before any use and do not call again once
* the object is available to other threads */
diff --git a/firmware/kernel/pthread/thread.c b/firmware/kernel/pthread/thread.c
index a80ce876e8..354a946698 100644
--- a/firmware/kernel/pthread/thread.c
+++ b/firmware/kernel/pthread/thread.c
@@ -194,23 +194,6 @@ static void remove_from_list_l(struct thread_entry **list,
thread->l.next->l.prev = thread->l.prev;
}
-unsigned int thread_queue_wake(struct thread_entry **list)
-{
- unsigned int result = THREAD_NONE;
-
- for (;;)
- {
- unsigned int rc = wakeup_thread(list);
-
- if (rc == THREAD_NONE)
- break;
-
- result |= rc;
- }
-
- return result;
-}
-
/* for block_thread(), _w_tmp() and wakeup_thread() t->lock must point
* to a corelock instance, and this corelock must be held by the caller */
void block_thread_switch(struct thread_entry *t, struct corelock *cl)
diff --git a/firmware/kernel/queue.c b/firmware/kernel/queue.c
index c8beb908b6..0ba7d7e00b 100644
--- a/firmware/kernel/queue.c
+++ b/firmware/kernel/queue.c
@@ -18,16 +18,10 @@
* KIND, either express or implied.
*
****************************************************************************/
-
#include <string.h>
-#include "config.h"
-#include "kernel.h"
-#include "system.h"
-#include "queue.h"
-#include "corelock.h"
#include "kernel-internal.h"
+#include "queue.h"
#include "general.h"
-#include "panic.h"
/* This array holds all queues that are initiated. It is used for broadcast. */
static struct
diff --git a/firmware/kernel/semaphore.c b/firmware/kernel/semaphore.c
index b6ce7fd742..1505038fbc 100644
--- a/firmware/kernel/semaphore.c
+++ b/firmware/kernel/semaphore.c
@@ -18,18 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
-
-
-/****************************************************************************
- * Simple mutex functions ;)
- ****************************************************************************/
-
-#include <stdbool.h>
-#include "config.h"
-#include "kernel.h"
-#include "semaphore.h"
#include "kernel-internal.h"
-#include "thread-internal.h"
+#include "semaphore.h"
/****************************************************************************
* Simple semaphore functions ;)
diff --git a/firmware/kernel/thread-common.c b/firmware/kernel/thread-common.c
new file mode 100644
index 0000000000..b8b8ffbd4c
--- /dev/null
+++ b/firmware/kernel/thread-common.c
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Ulf Ralberg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "thread-internal.h"
+#include "system.h"
+
+/*---------------------------------------------------------------------------
+ * Wakeup an entire queue of threads - returns bitwise-or of return bitmask
+ * from each operation or THREAD_NONE of nothing was awakened. Object owning
+ * the queue must be locked first.
+ *
+ * INTERNAL: Intended for use by kernel objects and not for programs.
+ *---------------------------------------------------------------------------
+ */
+unsigned int thread_queue_wake(struct thread_entry **list)
+{
+ unsigned result = THREAD_NONE;
+
+ for (;;)
+ {
+ unsigned int rc = wakeup_thread(list, WAKEUP_DEFAULT);
+
+ if (rc == THREAD_NONE)
+ break; /* No more threads */
+
+ result |= rc;
+ }
+
+ return result;
+}
+
+
+/** Debug screen stuff **/
+
+/*---------------------------------------------------------------------------
+ * returns the stack space used in bytes
+ *---------------------------------------------------------------------------
+ */
+static unsigned int stack_usage(uintptr_t *stackptr, size_t stack_size)
+{
+ unsigned int usage = 0;
+ unsigned int stack_words = stack_size / sizeof (uintptr_t);
+
+ for (unsigned int i = 0; i < stack_words; i++)
+ {
+ if (stackptr[i] != DEADBEEF)
+ {
+ usage = (stack_words - i) * 100 / stack_words;
+ break;
+ }
+ }
+
+ return usage;
+}
+
+#if NUM_CORES > 1
+/*---------------------------------------------------------------------------
+ * Returns the maximum percentage of the core's idle stack ever used during
+ * runtime.
+ *---------------------------------------------------------------------------
+ */
+int core_get_debug_info(unsigned int core, struct core_debug_info *infop)
+{
+ extern uintptr_t * const idle_stacks[NUM_CORES];
+
+ if (core >= NUM_CORES || !infop)
+ return -1;
+
+ infop->idle_stack_usage = stack_usage(idle_stacks[core], IDLE_STACK_SIZE);
+ return 1;
+}
+#endif /* NUM_CORES > 1 */
+
+int thread_get_debug_info(unsigned int thread_id,
+ struct thread_debug_info *infop)
+{
+ static const char status_chars[THREAD_NUM_STATES+1] =
+ {
+ [0 ... THREAD_NUM_STATES] = '?',
+ [STATE_RUNNING] = 'R',
+ [STATE_BLOCKED] = 'B',
+ [STATE_SLEEPING] = 'S',
+ [STATE_BLOCKED_W_TMO] = 'T',
+ [STATE_FROZEN] = 'F',
+ [STATE_KILLED] = 'K',
+ };
+
+ if (!infop)
+ return -1;
+
+ unsigned int slot = THREAD_ID_SLOT(thread_id);
+ if (slot >= MAXTHREADS)
+ return -1;
+
+ extern struct thread_entry threads[MAXTHREADS];
+ struct thread_entry *thread = &threads[slot];
+
+ int oldlevel = disable_irq_save();
+ LOCK_THREAD(thread);
+
+ unsigned int state = thread->state;
+
+ if (state != STATE_KILLED)
+ {
+ const char *name = thread->name;
+ if (!name)
+ name = "";
+
+ bool cpu_boost = false;
+#ifdef HAVE_SCHEDULER_BOOSTCTRL
+ cpu_boost = thread->cpu_boost;
+#endif
+ infop->stack_usage = stack_usage(thread->stack, thread->stack_size);
+#if NUM_CORES > 1
+ infop->core = thread->core;
+#endif
+#ifdef HAVE_PRIORITY_SCHEDULING
+ infop->base_priority = thread->base_priority;
+ infop->current_priority = thread->priority;
+#endif
+
+ snprintf(infop->statusstr, sizeof (infop->statusstr), "%c%c",
+ cpu_boost ? '+' : (state == STATE_RUNNING ? '*' : ' '),
+ status_chars[state]);
+
+ const char *fmt = *name ? "%s" : "%s%08lX";
+ snprintf(infop->name, sizeof (infop->name), fmt, name,
+ thread->id);
+ }
+
+ UNLOCK_THREAD(thread);
+ restore_irq(oldlevel);
+
+ return state == STATE_KILLED ? 0 : 1;
+}
diff --git a/firmware/kernel/thread-internal.h b/firmware/kernel/thread-internal.h
index c2acdfbaa9..894bd1fe7c 100644
--- a/firmware/kernel/thread-internal.h
+++ b/firmware/kernel/thread-internal.h
@@ -18,15 +18,13 @@
* KIND, either express or implied.
*
****************************************************************************/
+#ifndef THREAD_INTERNAL_H
+#define THREAD_INTERNAL_H
-#ifndef THREAD_H
-#define THREAD_H
-
-#include "config.h"
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include "gcc_extensions.h"
+#include "thread.h"
+#include <stdio.h>
+#include "panic.h"
+#include "debug.h"
/*
* We need more stack when we run under a host
@@ -48,23 +46,6 @@ struct regs
#include "asm/thread.h"
#endif /* HAVE_SDL_THREADS */
-#ifdef CPU_PP
-#ifdef HAVE_CORELOCK_OBJECT
-/* No reliable atomic instruction available - use Peterson's algorithm */
-struct corelock
-{
- volatile unsigned char myl[NUM_CORES];
- volatile unsigned char turn;
-} __attribute__((packed));
-
-/* Too big to inline everywhere */
-void corelock_init(struct corelock *cl);
-void corelock_lock(struct corelock *cl);
-int corelock_try_lock(struct corelock *cl);
-void corelock_unlock(struct corelock *cl);
-#endif /* HAVE_CORELOCK_OBJECT */
-#endif /* CPU_PP */
-
/* NOTE: The use of the word "queue" may also refer to a linked list of
threads being maintained that are normally dealt with in FIFO order
and not necessarily kernel event_queue */
@@ -84,58 +65,43 @@ enum
TIMEOUT_STATE_FIRST = STATE_SLEEPING,
};
-#if NUM_CORES > 1
-/* Pointer value for name field to indicate thread is being killed. Using
- * an alternate STATE_* won't work since that would interfere with operation
- * while the thread is still running. */
-#define THREAD_DESTRUCT ((const char *)~(intptr_t)0)
-#endif
+#ifdef HAVE_PRIORITY_SCHEDULING
-/* Link information for lists thread is in */
-struct thread_entry; /* forward */
-struct thread_list
+/* Quick-disinherit of priority elevation. Must be a running thread. */
+void priority_disinherit(struct thread_entry *thread, struct blocker *bl);
+
+struct priority_distribution
{
- struct thread_entry *prev; /* Previous thread in a list */
- struct thread_entry *next; /* Next thread in a list */
+ uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */
+ priobit_t mask; /* Bitmask of hist entries that are not zero */
};
-#ifndef HAVE_CORELOCK_OBJECT
-/* No atomic corelock op needed or just none defined */
-#define corelock_init(cl)
-#define corelock_lock(cl)
-#define corelock_try_lock(cl)
-#define corelock_unlock(cl)
-#endif /* HAVE_CORELOCK_OBJECT */
+#endif /* HAVE_PRIORITY_SCHEDULING */
-#ifdef HAVE_PRIORITY_SCHEDULING
-struct blocker
+#ifdef HAVE_CORELOCK_OBJECT
+/* Operations to be performed just before stopping a thread and starting
+ a new one if specified before calling switch_thread */
+enum
{
- struct thread_entry * volatile thread; /* thread blocking other threads
- (aka. object owner) */
- int priority; /* highest priority waiter */
- struct thread_entry * (*wakeup_protocol)(struct thread_entry *thread);
+ TBOP_CLEAR = 0, /* No operation to do */
+ TBOP_UNLOCK_CORELOCK, /* Unlock a corelock variable */
+ TBOP_SWITCH_CORE, /* Call the core switch preparation routine */
};
-/* Choices of wakeup protocol */
-
-/* For transfer of object ownership by one thread to another thread by
- * the owning thread itself (mutexes) */
-struct thread_entry *
- wakeup_priority_protocol_transfer(struct thread_entry *thread);
-
-/* For release by owner where ownership doesn't change - other threads,
- * interrupts, timeouts, etc. (mutex timeout, queues) */
-struct thread_entry *
- wakeup_priority_protocol_release(struct thread_entry *thread);
-
-
-struct priority_distribution
+struct thread_blk_ops
{
- uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */
- uint32_t mask; /* Bitmask of hist entries that are not zero */
+ struct corelock *cl_p; /* pointer to corelock */
+ unsigned char flags; /* TBOP_* flags */
};
+#endif /* NUM_CORES > 1 */
-#endif /* HAVE_PRIORITY_SCHEDULING */
+/* Link information for lists thread is in */
+struct thread_entry; /* forward */
+struct thread_list
+{
+ struct thread_entry *prev; /* Previous thread in a list */
+ struct thread_entry *next; /* Next thread in a list */
+};
/* Information kept in each thread slot
* members are arranged according to size - largest first - in order
@@ -183,6 +149,8 @@ struct thread_entry
volatile intptr_t retval; /* Return value from a blocked operation/
misc. use */
#endif
+ uint32_t id; /* Current slot id */
+ int __errno; /* Thread error number (errno tls) */
#ifdef HAVE_PRIORITY_SCHEDULING
/* Priority summary of owned objects that support inheritance */
struct blocker *blocker; /* Pointer to blocker when this thread is blocked
@@ -198,7 +166,6 @@ struct thread_entry
unsigned char priority; /* Scheduled priority (higher of base or
all threads blocked by this one) */
#endif
- uint16_t id; /* Current slot id */
unsigned short stack_size; /* Size of stack in bytes */
unsigned char state; /* Thread slot state (STATE_*) */
#ifdef HAVE_SCHEDULER_BOOSTCTRL
@@ -209,30 +176,6 @@ struct thread_entry
#endif
};
-/*** Macros for internal use ***/
-/* Thread ID, 16 bits = |VVVVVVVV|SSSSSSSS| */
-#define THREAD_ID_VERSION_SHIFT 8
-#define THREAD_ID_VERSION_MASK 0xff00
-#define THREAD_ID_SLOT_MASK 0x00ff
-#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n))
-
-#ifdef HAVE_CORELOCK_OBJECT
-/* Operations to be performed just before stopping a thread and starting
- a new one if specified before calling switch_thread */
-enum
-{
- TBOP_CLEAR = 0, /* No operation to do */
- TBOP_UNLOCK_CORELOCK, /* Unlock a corelock variable */
- TBOP_SWITCH_CORE, /* Call the core switch preparation routine */
-};
-
-struct thread_blk_ops
-{
- struct corelock *cl_p; /* pointer to corelock */
- unsigned char flags; /* TBOP_* flags */
-};
-#endif /* NUM_CORES > 1 */
-
/* Information kept for each core
* Members are arranged for the same reason as in thread_entry
*/
@@ -256,61 +199,45 @@ struct core_entry
#endif /* NUM_CORES */
};
-#ifdef HAVE_PRIORITY_SCHEDULING
-#define IF_PRIO(...) __VA_ARGS__
-#define IFN_PRIO(...)
-#else
-#define IF_PRIO(...)
-#define IFN_PRIO(...) __VA_ARGS__
-#endif
-
-void core_idle(void);
-void core_wake(IF_COP_VOID(unsigned int core));
-
-/* Initialize the scheduler */
-void init_threads(void) INIT_ATTR;
+/* Thread ID, 32 bits = |VVVVVVVV|VVVVVVVV|VVVVVVVV|SSSSSSSS| */
+#define THREAD_ID_VERSION_SHIFT 8
+#define THREAD_ID_VERSION_MASK 0xffffff00
+#define THREAD_ID_SLOT_MASK 0x000000ff
+#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n))
+#define THREAD_ID_SLOT(id) ((id) & THREAD_ID_SLOT_MASK)
-/* Allocate a thread in the scheduler */
-#define CREATE_THREAD_FROZEN 0x00000001 /* Thread is frozen at create time */
-unsigned int create_thread(void (*function)(void),
- void* stack, size_t stack_size,
- unsigned flags, const char *name
- IF_PRIO(, int priority)
- IF_COP(, unsigned int core));
+/* Thread locking */
+#if NUM_CORES > 1
+#define LOCK_THREAD(thread) \
+ ({ corelock_lock(&(thread)->slot_cl); })
+#define TRY_LOCK_THREAD(thread) \
+ ({ corelock_try_lock(&(thread)->slot_cl); })
+#define UNLOCK_THREAD(thread) \
+ ({ corelock_unlock(&(thread)->slot_cl); })
+#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
+ ({ unsigned int _core = (thread)->core; \
+ cores[_core].blk_ops.flags |= TBOP_UNLOCK_CORELOCK; \
+ cores[_core].blk_ops.cl_p = &(thread)->slot_cl; })
+#else /* NUM_CORES == 1*/
+#define LOCK_THREAD(thread) \
+ ({ (void)(thread); })
+#define TRY_LOCK_THREAD(thread) \
+ ({ (void)(thread); })
+#define UNLOCK_THREAD(thread) \
+ ({ (void)(thread); })
+#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
+ ({ (void)(thread); })
+#endif /* NUM_CORES */
-/* Set and clear the CPU frequency boost flag for the calling thread */
-#ifdef HAVE_SCHEDULER_BOOSTCTRL
-void trigger_cpu_boost(void);
-void cancel_cpu_boost(void);
-#else
-#define trigger_cpu_boost() do { } while(0)
-#define cancel_cpu_boost() do { } while(0)
-#endif
-/* Return thread entry from id */
-struct thread_entry *thread_id_entry(unsigned int thread_id);
-/* Make a frozed thread runnable (when started with CREATE_THREAD_FROZEN).
- * Has no effect on a thread not frozen. */
-void thread_thaw(unsigned int thread_id);
-/* Wait for a thread to exit */
-void thread_wait(unsigned int thread_id);
-/* Exit the current thread */
-void thread_exit(void) NORETURN_ATTR;
-#if defined(DEBUG) || defined(ROCKBOX_HAS_LOGF)
-#define ALLOW_REMOVE_THREAD
-/* Remove a thread from the scheduler */
-void remove_thread(unsigned int thread_id);
-#endif
+#define DEADBEEF ((uintptr_t)0xdeadbeefdeadbeefull)
/* Switch to next runnable thread */
void switch_thread(void);
/* Blocks a thread for at least the specified number of ticks (0 = wait until
* next tick) */
void sleep_thread(int ticks);
-/* Indefinitely blocks the current thread on a thread queue */
-void block_thread(struct thread_entry *current);
-/* Blocks the current thread on a thread queue until explicitely woken or
- * the timeout is reached */
-void block_thread_w_tmo(struct thread_entry *current, int timeout);
+/* Blocks the current thread on a thread queue (< 0 == infinite) */
+void block_thread(struct thread_entry *current, int timeout);
/* Return bit flags for thread wakeup */
#define THREAD_NONE 0x0 /* No thread woken up (exclusive) */
@@ -322,12 +249,25 @@ void block_thread_w_tmo(struct thread_entry *current, int timeout);
unsigned int thread_queue_wake(struct thread_entry **list);
/* Wakeup a thread at the head of a list */
-unsigned int wakeup_thread(struct thread_entry **list);
+enum wakeup_thread_protocol
+{
+ WAKEUP_DEFAULT,
+ WAKEUP_TRANSFER,
+ WAKEUP_RELEASE,
+ WAKEUP_TRANSFER_MULTI,
+};
+
+unsigned int wakeup_thread_(struct thread_entry **list
+ IF_PRIO(, enum wakeup_thread_protocol proto));
#ifdef HAVE_PRIORITY_SCHEDULING
-int thread_set_priority(unsigned int thread_id, int priority);
-int thread_get_priority(unsigned int thread_id);
+#define wakeup_thread(list, proto) \
+ wakeup_thread_((list), (proto))
+#else /* !HAVE_PRIORITY_SCHEDULING */
+#define wakeup_thread(list, proto...) \
+ wakeup_thread_((list));
#endif /* HAVE_PRIORITY_SCHEDULING */
+
#ifdef HAVE_IO_PRIORITY
void thread_set_io_priority(unsigned int thread_id, int io_priority);
int thread_get_io_priority(unsigned int thread_id);
@@ -339,19 +279,14 @@ unsigned int switch_core(unsigned int new_core);
/* Return the id of the calling thread. */
unsigned int thread_self(void);
-/* Return the thread_entry for the calling thread.
- * INTERNAL: Intended for use by kernel and not for programs. */
+/* Return the thread_entry for the calling thread */
struct thread_entry* thread_self_entry(void);
-/* Debugging info - only! */
-int thread_stack_usage(const struct thread_entry *thread);
-#if NUM_CORES > 1
-int idle_stack_usage(unsigned int core);
-#endif
-void thread_get_name(char *buffer, int size,
- struct thread_entry *thread);
+/* Return thread entry from id */
+struct thread_entry *thread_id_entry(unsigned int thread_id);
+
#ifdef RB_PROFILE
void profile_thread(void);
#endif
-#endif /* THREAD_H */
+#endif /* THREAD_INTERNAL_H */
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 @@
#undef _FORTIFY_SOURCE
#endif
-#include <stdbool.h>
-#include <stdio.h>
-#include "thread.h"
-#include "panic.h"
-#include "system.h"
+#include "thread-internal.h"
#include "kernel.h"
#include "cpu.h"
#include "string.h"
@@ -40,8 +36,6 @@
#include <profile.h>
#endif
#include "core_alloc.h"
-#include "gcc_extensions.h"
-#include "corelock.h"
/****************************************************************************
* ATTENTION!! *
@@ -131,7 +125,6 @@
/* Cast to the the machine pointer size, whose size could be < 4 or > 32
* (someday :). */
-#define DEADBEEF ((uintptr_t)0xdeadbeefdeadbeefull)
static struct core_entry cores[NUM_CORES] IBSS_ATTR;
struct thread_entry threads[MAXTHREADS] IBSS_ATTR;
@@ -204,57 +197,36 @@ void switch_thread(void)
* End Processor-specific section
***************************************************************************/
-#if THREAD_EXTRA_CHECKS
-static void thread_panicf(const char *msg, struct thread_entry *thread)
+static NO_INLINE
+ void thread_panicf(const char *msg, struct thread_entry *thread)
{
IF_COP( const unsigned int core = thread->core; )
- static char name[32];
- thread_get_name(name, 32, thread);
+ static char namebuf[sizeof (((struct thread_debug_info *)0)->name)];
+ const char *name = thread->name;
+ if (!name)
+ name = "";
+ snprintf(namebuf, sizeof (namebuf), *name ? "%s" : "%s%08lX",
+ name, (unsigned long)thread->id);
panicf ("%s %s" IF_COP(" (%d)"), msg, name IF_COP(, core));
}
+
static void thread_stkov(struct thread_entry *thread)
{
thread_panicf("Stkov", thread);
}
+
+#if THREAD_EXTRA_CHECKS
#define THREAD_PANICF(msg, thread) \
thread_panicf(msg, thread)
#define THREAD_ASSERT(exp, msg, thread) \
({ if (!({ exp; })) thread_panicf((msg), (thread)); })
#else
-static void thread_stkov(struct thread_entry *thread)
-{
- IF_COP( const unsigned int core = thread->core; )
- static char name[32];
- thread_get_name(name, 32, thread);
- panicf("Stkov %s" IF_COP(" (%d)"), name IF_COP(, core));
-}
-#define THREAD_PANICF(msg, thread)
-#define THREAD_ASSERT(exp, msg, thread)
+#define THREAD_PANICF(msg, thread) \
+ do {} while (0)
+#define THREAD_ASSERT(exp, msg, thread) \
+ do {} while (0)
#endif /* THREAD_EXTRA_CHECKS */
-/* Thread locking */
-#if NUM_CORES > 1
-#define LOCK_THREAD(thread) \
- ({ corelock_lock(&(thread)->slot_cl); })
-#define TRY_LOCK_THREAD(thread) \
- ({ corelock_try_lock(&(thread)->slot_cl); })
-#define UNLOCK_THREAD(thread) \
- ({ corelock_unlock(&(thread)->slot_cl); })
-#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
- ({ unsigned int _core = (thread)->core; \
- cores[_core].blk_ops.flags |= TBOP_UNLOCK_CORELOCK; \
- cores[_core].blk_ops.cl_p = &(thread)->slot_cl; })
-#else
-#define LOCK_THREAD(thread) \
- ({ (void)(thread); })
-#define TRY_LOCK_THREAD(thread) \
- ({ (void)(thread); })
-#define UNLOCK_THREAD(thread) \
- ({ (void)(thread); })
-#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
- ({ (void)(thread); })
-#endif
-
/* RTR list */
#define RTR_LOCK(core) \
({ corelock_lock(&cores[core].rtr_cl); })
@@ -993,27 +965,6 @@ static void wakeup_thread_release(struct thread_entry *thread)
inherit_priority(bl, bl, blt, newblpr);
}
-/*---------------------------------------------------------------------------
- * No threads must be blocked waiting for this thread except for it to exit.
- * The alternative is more elaborate cleanup and object registration code.
- * Check this for risk of silent data corruption when objects with
- * inheritable blocking are abandoned by the owner - not precise but may
- * catch something.
- *---------------------------------------------------------------------------
- */
-static void __attribute__((noinline)) check_for_obj_waiters(
- const char *function, struct thread_entry *thread)
-{
- /* Only one bit in the mask should be set with a frequency on 1 which
- * represents the thread's own base priority */
- if (priobit_popcount(&thread->pdist.mask) != 1 ||
- thread->pdist.hist[priobit_ffs(&thread->pdist.mask)] > 1)
- {
- unsigned char name[32];
- thread_get_name(name, 32, thread);
- panicf("%s->%s with obj. waiters", function, name);
- }
-}
#endif /* HAVE_PRIORITY_SCHEDULING */
/*---------------------------------------------------------------------------
@@ -1520,31 +1471,6 @@ void block_thread(struct thread_entry *current, int timeout)
}
/*---------------------------------------------------------------------------
- * Wakeup an entire queue of threads - returns bitwise-or of return bitmask
- * from each operation or THREAD_NONE of nothing was awakened. Object owning
- * the queue must be locked first.
- *
- * INTERNAL: Intended for use by kernel objects and not for programs.
- *---------------------------------------------------------------------------
- */
-unsigned int thread_queue_wake(struct thread_entry **list)
-{
- unsigned result = THREAD_NONE;
-
- for (;;)
- {
- unsigned int rc = wakeup_thread(list, WAKEUP_DEFAULT);
-
- if (rc == THREAD_NONE)
- break; /* No more threads */
-
- result |= rc;
- }
-
- return result;
-}
-
-/*---------------------------------------------------------------------------
* Assign the thread slot a new ID. Version is 0x00000100..0xffffff00.
*---------------------------------------------------------------------------
*/
@@ -1580,7 +1506,7 @@ static struct thread_entry * find_empty_thread_slot(void)
struct thread_entry *t = &threads[n];
LOCK_THREAD(t);
- if (t->state == STATE_KILLED IF_COP( && t->name != THREAD_DESTRUCT ))
+ if (t->state == STATE_KILLED)
{
/* Slot is empty - leave it locked and caller will unlock */
thread = t;
@@ -1836,21 +1762,14 @@ void thread_exit(void)
corelock_lock(&current->waiter_cl);
LOCK_THREAD(current);
-#if defined (ALLOW_REMOVE_THREAD) && NUM_CORES > 1
- if (current->name == THREAD_DESTRUCT)
- {
- /* Thread being killed - become a waiter */
- unsigned int id = current->id;
- UNLOCK_THREAD(current);
- corelock_unlock(&current->waiter_cl);
- thread_wait(id);
- THREAD_PANICF("thread_exit->WK:*R", current);
- }
-#endif
-
#ifdef HAVE_PRIORITY_SCHEDULING
- check_for_obj_waiters("thread_exit", current);
-#endif
+ /* Only one bit in the mask should be set with a frequency on 1 which
+ * represents the thread's own base priority otherwise threads are waiting
+ * on an abandoned object */
+ if (priobit_popcount(&current->pdist.mask) != 1 ||
+ current->pdist.hist[priobit_ffs(&current->pdist.mask)] > 1)
+ thread_panicf("abandon ship!", current);
+#endif /* HAVE_PRIORITY_SCHEDULING */
if (current->tmo.prev != NULL)
{
@@ -1872,186 +1791,6 @@ void thread_exit(void)
thread_final_exit(current);
}
-#ifdef ALLOW_REMOVE_THREAD
-/*---------------------------------------------------------------------------
- * Remove a thread from the scheduler. Not The Right Way to Do Things in
- * normal programs.
- *
- * Parameter is the ID as returned from create_thread().
- *
- * Use with care on threads that are not under careful control as this may
- * leave various objects in an undefined state.
- *---------------------------------------------------------------------------
- */
-void remove_thread(unsigned int thread_id)
-{
-#ifdef HAVE_CORELOCK_OBJECT
- /* core is not constant here because of core switching */
- unsigned int core = CURRENT_CORE;
- unsigned int old_core = NUM_CORES;
- struct corelock *ocl = NULL;
-#else
- const unsigned int core = CURRENT_CORE;
-#endif
- struct thread_entry *current = cores[core].running;
- struct thread_entry *thread = thread_id_entry(thread_id);
-
- unsigned state;
- int oldlevel;
-
- if (thread == current)
- thread_exit(); /* Current thread - do normal exit */
-
- oldlevel = disable_irq_save();
-
- corelock_lock(&thread->waiter_cl);
- LOCK_THREAD(thread);
-
- state = thread->state;
-
- if (thread->id != thread_id || state == STATE_KILLED)
- goto thread_killed;
-
-#if NUM_CORES > 1
- if (thread->name == THREAD_DESTRUCT)
- {
- /* Thread being killed - become a waiter */
- UNLOCK_THREAD(thread);
- corelock_unlock(&thread->waiter_cl);
- restore_irq(oldlevel);
- thread_wait(thread_id);
- return;
- }
-
- thread->name = THREAD_DESTRUCT; /* Slot can't be used for now */
-
-#ifdef HAVE_PRIORITY_SCHEDULING
- check_for_obj_waiters("remove_thread", thread);
-#endif
-
- if (thread->core != core)
- {
- /* Switch cores and safely extract the thread there */
- /* Slot HAS to be unlocked or a deadlock could occur which means other
- * threads have to be guided into becoming thread waiters if they
- * attempt to remove it. */
- unsigned int new_core = thread->core;
-
- corelock_unlock(&thread->waiter_cl);
-
- UNLOCK_THREAD(thread);
- restore_irq(oldlevel);
-
- old_core = switch_core(new_core);
-
- oldlevel = disable_irq_save();
-
- corelock_lock(&thread->waiter_cl);
- LOCK_THREAD(thread);
-
- state = thread->state;
- core = new_core;
- /* Perform the extraction and switch ourselves back to the original
- processor */
- }
-#endif /* NUM_CORES > 1 */
-
- if (thread->tmo.prev != NULL)
- {
- /* Clean thread off the timeout list if a timeout check hasn't
- * run yet */
- remove_from_list_tmo(thread);
- }
-
-#ifdef HAVE_SCHEDULER_BOOSTCTRL
- /* Cancel CPU boost if any */
- boost_thread(thread, false);
-#endif
-
-IF_COP( retry_state: )
-
- switch (state)
- {
- case STATE_RUNNING:
- RTR_LOCK(core);
- /* Remove thread from ready to run tasks */
- remove_from_list_l(&cores[core].running, thread);
- rtr_subtract_entry(core, thread->priority);
- RTR_UNLOCK(core);
- break;
- case STATE_BLOCKED:
- case STATE_BLOCKED_W_TMO:
- /* Remove thread from the queue it's blocked on - including its
- * own if waiting there */
-#if NUM_CORES > 1
- if (&thread->waiter_cl != thread->obj_cl)
- {
- ocl = thread->obj_cl;
-
- if (UNLIKELY(corelock_try_lock(ocl) == 0))
- {
- UNLOCK_THREAD(thread);
- corelock_lock(ocl);
- LOCK_THREAD(thread);
-
- if (UNLIKELY(thread->state != state))
- {
- /* Something woke the thread */
- state = thread->state;
- corelock_unlock(ocl);
- goto retry_state;
- }
- }
- }
-#endif
-#ifdef HAVE_WAKEUP_EXT_CB
- if (thread->wakeup_ext_cb != NULL)
- thread->wakeup_ext_cb(thread);
-#endif
-
-#ifdef HAVE_PRIORITY_SCHEDULING
- /* Remove thread's priority influence from its chain if needed */
- if (thread->blocker != NULL)
- wakeup_priority_protocol_release(thread);
- else
-#endif
- remove_from_list_l(thread->bqp, thread);
-
-#if NUM_CORES > 1
- if (ocl != NULL)
- corelock_unlock(ocl);
-#endif
- break;
- /* Otherwise thread is frozen and hasn't run yet */
- }
-
- new_thread_id(thread_id, thread);
- thread->state = STATE_KILLED;
-
- /* If thread was waiting on itself, it will have been removed above.
- * The wrong order would result in waking the thread first and deadlocking
- * since the slot is already locked. */
- thread_queue_wake(&thread->queue);
-
- thread->name = NULL;
-
-thread_killed: /* Thread was already killed */
- /* Removal complete - safe to unlock and reenable interrupts */
- corelock_unlock(&thread->waiter_cl);
- UNLOCK_THREAD(thread);
- restore_irq(oldlevel);
-
-#if NUM_CORES > 1
- if (old_core < NUM_CORES)
- {
- /* Did a removal on another processor's thread - switch back to
- native core */
- switch_core(old_core);
- }
-#endif
-}
-#endif /* ALLOW_REMOVE_THREAD */
-
#ifdef HAVE_PRIORITY_SCHEDULING
/*---------------------------------------------------------------------------
* 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)
return core;
}
- int oldlevel = disable_irq_save();
+ disable_irq();
LOCK_THREAD(current);
- if (current->name == THREAD_DESTRUCT)
- {
- /* Thread being killed - deactivate and let process complete */
- unsigned int id = current->id;
- UNLOCK_THREAD(current);
- restore_irq(oldlevel);
- thread_wait(id);
- /* Should never be reached */
- THREAD_PANICF("switch_core->D:*R", current);
- }
-
/* Get us off the running list for the current core */
RTR_LOCK(core);
remove_from_list_l(&cores[core].running, current);
@@ -2274,7 +2002,7 @@ unsigned int switch_core(unsigned int new_core)
* are safe to perform.
*---------------------------------------------------------------------------
*/
-void init_threads(void)
+void INIT_ATTR init_threads(void)
{
const unsigned int core = CURRENT_CORE;
struct thread_entry *thread;
@@ -2353,82 +2081,6 @@ void init_threads(void)
#endif
}
-/* Shared stack scan helper for thread_stack_usage and idle_stack_usage */
-#if NUM_CORES == 1
-static inline int stack_usage(uintptr_t *stackptr, size_t stack_size)
-#else
-static int stack_usage(uintptr_t *stackptr, size_t stack_size)
-#endif
-{
- unsigned int stack_words = stack_size / sizeof (uintptr_t);
- unsigned int i;
- int usage = 0;
-
- for (i = 0; i < stack_words; i++)
- {
- if (stackptr[i] != DEADBEEF)
- {
- usage = ((stack_words - i) * 100) / stack_words;
- break;
- }
- }
-
- return usage;
-}
-
-/*---------------------------------------------------------------------------
- * Returns the maximum percentage of stack a thread ever used while running.
- * NOTE: Some large buffer allocations that don't use enough the buffer to
- * overwrite stackptr[0] will not be seen.
- *---------------------------------------------------------------------------
- */
-int thread_stack_usage(const struct thread_entry *thread)
-{
- if (LIKELY(thread->stack_size > 0))
- return stack_usage(thread->stack, thread->stack_size);
- return 0;
-}
-
-#if NUM_CORES > 1
-/*---------------------------------------------------------------------------
- * Returns the maximum percentage of the core's idle stack ever used during
- * runtime.
- *---------------------------------------------------------------------------
- */
-int idle_stack_usage(unsigned int core)
-{
- return stack_usage(idle_stacks[core], IDLE_STACK_SIZE);
-}
-#endif
-
-/*---------------------------------------------------------------------------
- * Fills in the buffer with the specified thread's name. If the name is NULL,
- * empty, or the thread is in destruct state a formatted ID is written
- * instead.
- *---------------------------------------------------------------------------
- */
-void thread_get_name(char *buffer, int size,
- struct thread_entry *thread)
-{
- if (size <= 0)
- return;
-
- *buffer = '\0';
-
- if (thread)
- {
- /* Display thread name if one or ID if none */
- const char *name = thread->name;
- const char *fmt = "%s";
- if (name == NULL IF_COP(|| name == THREAD_DESTRUCT) || *name == '\0')
- {
- name = (const char *)(uintptr_t)thread->id;
- fmt = "%04lX";
- }
- snprintf(buffer, size, fmt, name);
- }
-}
-
/* Unless otherwise defined, do nothing */
#ifndef YIELD_KERNEL_HOOK
#define YIELD_KERNEL_HOOK() false