summaryrefslogtreecommitdiff
path: root/firmware/kernel/thread-internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/kernel/thread-internal.h')
-rw-r--r--firmware/kernel/thread-internal.h237
1 files changed, 86 insertions, 151 deletions
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 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#ifndef THREAD_INTERNAL_H
22#define THREAD_INTERNAL_H
21 23
22#ifndef THREAD_H 24#include "thread.h"
23#define THREAD_H 25#include <stdio.h>
24 26#include "panic.h"
25#include "config.h" 27#include "debug.h"
26#include <inttypes.h>
27#include <stddef.h>
28#include <stdbool.h>
29#include "gcc_extensions.h"
30 28
31/* 29/*
32 * We need more stack when we run under a host 30 * We need more stack when we run under a host
@@ -48,23 +46,6 @@ struct regs
48#include "asm/thread.h" 46#include "asm/thread.h"
49#endif /* HAVE_SDL_THREADS */ 47#endif /* HAVE_SDL_THREADS */
50 48
51#ifdef CPU_PP
52#ifdef HAVE_CORELOCK_OBJECT
53/* No reliable atomic instruction available - use Peterson's algorithm */
54struct corelock
55{
56 volatile unsigned char myl[NUM_CORES];
57 volatile unsigned char turn;
58} __attribute__((packed));
59
60/* Too big to inline everywhere */
61void corelock_init(struct corelock *cl);
62void corelock_lock(struct corelock *cl);
63int corelock_try_lock(struct corelock *cl);
64void corelock_unlock(struct corelock *cl);
65#endif /* HAVE_CORELOCK_OBJECT */
66#endif /* CPU_PP */
67
68/* NOTE: The use of the word "queue" may also refer to a linked list of 49/* NOTE: The use of the word "queue" may also refer to a linked list of
69 threads being maintained that are normally dealt with in FIFO order 50 threads being maintained that are normally dealt with in FIFO order
70 and not necessarily kernel event_queue */ 51 and not necessarily kernel event_queue */
@@ -84,58 +65,43 @@ enum
84 TIMEOUT_STATE_FIRST = STATE_SLEEPING, 65 TIMEOUT_STATE_FIRST = STATE_SLEEPING,
85}; 66};
86 67
87#if NUM_CORES > 1 68#ifdef HAVE_PRIORITY_SCHEDULING
88/* Pointer value for name field to indicate thread is being killed. Using
89 * an alternate STATE_* won't work since that would interfere with operation
90 * while the thread is still running. */
91#define THREAD_DESTRUCT ((const char *)~(intptr_t)0)
92#endif
93 69
94/* Link information for lists thread is in */ 70/* Quick-disinherit of priority elevation. Must be a running thread. */
95struct thread_entry; /* forward */ 71void priority_disinherit(struct thread_entry *thread, struct blocker *bl);
96struct thread_list 72
73struct priority_distribution
97{ 74{
98 struct thread_entry *prev; /* Previous thread in a list */ 75 uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */
99 struct thread_entry *next; /* Next thread in a list */ 76 priobit_t mask; /* Bitmask of hist entries that are not zero */
100}; 77};
101 78
102#ifndef HAVE_CORELOCK_OBJECT 79#endif /* HAVE_PRIORITY_SCHEDULING */
103/* No atomic corelock op needed or just none defined */
104#define corelock_init(cl)
105#define corelock_lock(cl)
106#define corelock_try_lock(cl)
107#define corelock_unlock(cl)
108#endif /* HAVE_CORELOCK_OBJECT */
109 80
110#ifdef HAVE_PRIORITY_SCHEDULING 81#ifdef HAVE_CORELOCK_OBJECT
111struct blocker 82/* Operations to be performed just before stopping a thread and starting
83 a new one if specified before calling switch_thread */
84enum
112{ 85{
113 struct thread_entry * volatile thread; /* thread blocking other threads 86 TBOP_CLEAR = 0, /* No operation to do */
114 (aka. object owner) */ 87 TBOP_UNLOCK_CORELOCK, /* Unlock a corelock variable */
115 int priority; /* highest priority waiter */ 88 TBOP_SWITCH_CORE, /* Call the core switch preparation routine */
116 struct thread_entry * (*wakeup_protocol)(struct thread_entry *thread);
117}; 89};
118 90
119/* Choices of wakeup protocol */ 91struct thread_blk_ops
120
121/* For transfer of object ownership by one thread to another thread by
122 * the owning thread itself (mutexes) */
123struct thread_entry *
124 wakeup_priority_protocol_transfer(struct thread_entry *thread);
125
126/* For release by owner where ownership doesn't change - other threads,
127 * interrupts, timeouts, etc. (mutex timeout, queues) */
128struct thread_entry *
129 wakeup_priority_protocol_release(struct thread_entry *thread);
130
131
132struct priority_distribution
133{ 92{
134 uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */ 93 struct corelock *cl_p; /* pointer to corelock */
135 uint32_t mask; /* Bitmask of hist entries that are not zero */ 94 unsigned char flags; /* TBOP_* flags */
136}; 95};
96#endif /* NUM_CORES > 1 */
137 97
138#endif /* HAVE_PRIORITY_SCHEDULING */ 98/* Link information for lists thread is in */
99struct thread_entry; /* forward */
100struct thread_list
101{
102 struct thread_entry *prev; /* Previous thread in a list */
103 struct thread_entry *next; /* Next thread in a list */
104};
139 105
140/* Information kept in each thread slot 106/* Information kept in each thread slot
141 * members are arranged according to size - largest first - in order 107 * members are arranged according to size - largest first - in order
@@ -183,6 +149,8 @@ struct thread_entry
183 volatile intptr_t retval; /* Return value from a blocked operation/ 149 volatile intptr_t retval; /* Return value from a blocked operation/
184 misc. use */ 150 misc. use */
185#endif 151#endif
152 uint32_t id; /* Current slot id */
153 int __errno; /* Thread error number (errno tls) */
186#ifdef HAVE_PRIORITY_SCHEDULING 154#ifdef HAVE_PRIORITY_SCHEDULING
187 /* Priority summary of owned objects that support inheritance */ 155 /* Priority summary of owned objects that support inheritance */
188 struct blocker *blocker; /* Pointer to blocker when this thread is blocked 156 struct blocker *blocker; /* Pointer to blocker when this thread is blocked
@@ -198,7 +166,6 @@ struct thread_entry
198 unsigned char priority; /* Scheduled priority (higher of base or 166 unsigned char priority; /* Scheduled priority (higher of base or
199 all threads blocked by this one) */ 167 all threads blocked by this one) */
200#endif 168#endif
201 uint16_t id; /* Current slot id */
202 unsigned short stack_size; /* Size of stack in bytes */ 169 unsigned short stack_size; /* Size of stack in bytes */
203 unsigned char state; /* Thread slot state (STATE_*) */ 170 unsigned char state; /* Thread slot state (STATE_*) */
204#ifdef HAVE_SCHEDULER_BOOSTCTRL 171#ifdef HAVE_SCHEDULER_BOOSTCTRL
@@ -209,30 +176,6 @@ struct thread_entry
209#endif 176#endif
210}; 177};
211 178
212/*** Macros for internal use ***/
213/* Thread ID, 16 bits = |VVVVVVVV|SSSSSSSS| */
214#define THREAD_ID_VERSION_SHIFT 8
215#define THREAD_ID_VERSION_MASK 0xff00
216#define THREAD_ID_SLOT_MASK 0x00ff
217#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n))
218
219#ifdef HAVE_CORELOCK_OBJECT
220/* Operations to be performed just before stopping a thread and starting
221 a new one if specified before calling switch_thread */
222enum
223{
224 TBOP_CLEAR = 0, /* No operation to do */
225 TBOP_UNLOCK_CORELOCK, /* Unlock a corelock variable */
226 TBOP_SWITCH_CORE, /* Call the core switch preparation routine */
227};
228
229struct thread_blk_ops
230{
231 struct corelock *cl_p; /* pointer to corelock */
232 unsigned char flags; /* TBOP_* flags */
233};
234#endif /* NUM_CORES > 1 */
235
236/* Information kept for each core 179/* Information kept for each core
237 * Members are arranged for the same reason as in thread_entry 180 * Members are arranged for the same reason as in thread_entry
238 */ 181 */
@@ -256,61 +199,45 @@ struct core_entry
256#endif /* NUM_CORES */ 199#endif /* NUM_CORES */
257}; 200};
258 201
259#ifdef HAVE_PRIORITY_SCHEDULING 202/* Thread ID, 32 bits = |VVVVVVVV|VVVVVVVV|VVVVVVVV|SSSSSSSS| */
260#define IF_PRIO(...) __VA_ARGS__ 203#define THREAD_ID_VERSION_SHIFT 8
261#define IFN_PRIO(...) 204#define THREAD_ID_VERSION_MASK 0xffffff00
262#else 205#define THREAD_ID_SLOT_MASK 0x000000ff
263#define IF_PRIO(...) 206#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n))
264#define IFN_PRIO(...) __VA_ARGS__ 207#define THREAD_ID_SLOT(id) ((id) & THREAD_ID_SLOT_MASK)
265#endif
266
267void core_idle(void);
268void core_wake(IF_COP_VOID(unsigned int core));
269
270/* Initialize the scheduler */
271void init_threads(void) INIT_ATTR;
272 208
273/* Allocate a thread in the scheduler */ 209/* Thread locking */
274#define CREATE_THREAD_FROZEN 0x00000001 /* Thread is frozen at create time */ 210#if NUM_CORES > 1
275unsigned int create_thread(void (*function)(void), 211#define LOCK_THREAD(thread) \
276 void* stack, size_t stack_size, 212 ({ corelock_lock(&(thread)->slot_cl); })
277 unsigned flags, const char *name 213#define TRY_LOCK_THREAD(thread) \
278 IF_PRIO(, int priority) 214 ({ corelock_try_lock(&(thread)->slot_cl); })
279 IF_COP(, unsigned int core)); 215#define UNLOCK_THREAD(thread) \
216 ({ corelock_unlock(&(thread)->slot_cl); })
217#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
218 ({ unsigned int _core = (thread)->core; \
219 cores[_core].blk_ops.flags |= TBOP_UNLOCK_CORELOCK; \
220 cores[_core].blk_ops.cl_p = &(thread)->slot_cl; })
221#else /* NUM_CORES == 1*/
222#define LOCK_THREAD(thread) \
223 ({ (void)(thread); })
224#define TRY_LOCK_THREAD(thread) \
225 ({ (void)(thread); })
226#define UNLOCK_THREAD(thread) \
227 ({ (void)(thread); })
228#define UNLOCK_THREAD_AT_TASK_SWITCH(thread) \
229 ({ (void)(thread); })
230#endif /* NUM_CORES */
280 231
281/* Set and clear the CPU frequency boost flag for the calling thread */ 232#define DEADBEEF ((uintptr_t)0xdeadbeefdeadbeefull)
282#ifdef HAVE_SCHEDULER_BOOSTCTRL
283void trigger_cpu_boost(void);
284void cancel_cpu_boost(void);
285#else
286#define trigger_cpu_boost() do { } while(0)
287#define cancel_cpu_boost() do { } while(0)
288#endif
289/* Return thread entry from id */
290struct thread_entry *thread_id_entry(unsigned int thread_id);
291/* Make a frozed thread runnable (when started with CREATE_THREAD_FROZEN).
292 * Has no effect on a thread not frozen. */
293void thread_thaw(unsigned int thread_id);
294/* Wait for a thread to exit */
295void thread_wait(unsigned int thread_id);
296/* Exit the current thread */
297void thread_exit(void) NORETURN_ATTR;
298#if defined(DEBUG) || defined(ROCKBOX_HAS_LOGF)
299#define ALLOW_REMOVE_THREAD
300/* Remove a thread from the scheduler */
301void remove_thread(unsigned int thread_id);
302#endif
303 233
304/* Switch to next runnable thread */ 234/* Switch to next runnable thread */
305void switch_thread(void); 235void switch_thread(void);
306/* Blocks a thread for at least the specified number of ticks (0 = wait until 236/* Blocks a thread for at least the specified number of ticks (0 = wait until
307 * next tick) */ 237 * next tick) */
308void sleep_thread(int ticks); 238void sleep_thread(int ticks);
309/* Indefinitely blocks the current thread on a thread queue */ 239/* Blocks the current thread on a thread queue (< 0 == infinite) */
310void block_thread(struct thread_entry *current); 240void block_thread(struct thread_entry *current, int timeout);
311/* Blocks the current thread on a thread queue until explicitely woken or
312 * the timeout is reached */
313void block_thread_w_tmo(struct thread_entry *current, int timeout);
314 241
315/* Return bit flags for thread wakeup */ 242/* Return bit flags for thread wakeup */
316#define THREAD_NONE 0x0 /* No thread woken up (exclusive) */ 243#define THREAD_NONE 0x0 /* No thread woken up (exclusive) */
@@ -322,12 +249,25 @@ void block_thread_w_tmo(struct thread_entry *current, int timeout);
322unsigned int thread_queue_wake(struct thread_entry **list); 249unsigned int thread_queue_wake(struct thread_entry **list);
323 250
324/* Wakeup a thread at the head of a list */ 251/* Wakeup a thread at the head of a list */
325unsigned int wakeup_thread(struct thread_entry **list); 252enum wakeup_thread_protocol
253{
254 WAKEUP_DEFAULT,
255 WAKEUP_TRANSFER,
256 WAKEUP_RELEASE,
257 WAKEUP_TRANSFER_MULTI,
258};
259
260unsigned int wakeup_thread_(struct thread_entry **list
261 IF_PRIO(, enum wakeup_thread_protocol proto));
326 262
327#ifdef HAVE_PRIORITY_SCHEDULING 263#ifdef HAVE_PRIORITY_SCHEDULING
328int thread_set_priority(unsigned int thread_id, int priority); 264#define wakeup_thread(list, proto) \
329int thread_get_priority(unsigned int thread_id); 265 wakeup_thread_((list), (proto))
266#else /* !HAVE_PRIORITY_SCHEDULING */
267#define wakeup_thread(list, proto...) \
268 wakeup_thread_((list));
330#endif /* HAVE_PRIORITY_SCHEDULING */ 269#endif /* HAVE_PRIORITY_SCHEDULING */
270
331#ifdef HAVE_IO_PRIORITY 271#ifdef HAVE_IO_PRIORITY
332void thread_set_io_priority(unsigned int thread_id, int io_priority); 272void thread_set_io_priority(unsigned int thread_id, int io_priority);
333int thread_get_io_priority(unsigned int thread_id); 273int thread_get_io_priority(unsigned int thread_id);
@@ -339,19 +279,14 @@ unsigned int switch_core(unsigned int new_core);
339/* Return the id of the calling thread. */ 279/* Return the id of the calling thread. */
340unsigned int thread_self(void); 280unsigned int thread_self(void);
341 281
342/* Return the thread_entry for the calling thread. 282/* Return the thread_entry for the calling thread */
343 * INTERNAL: Intended for use by kernel and not for programs. */
344struct thread_entry* thread_self_entry(void); 283struct thread_entry* thread_self_entry(void);
345 284
346/* Debugging info - only! */ 285/* Return thread entry from id */
347int thread_stack_usage(const struct thread_entry *thread); 286struct thread_entry *thread_id_entry(unsigned int thread_id);
348#if NUM_CORES > 1 287
349int idle_stack_usage(unsigned int core);
350#endif
351void thread_get_name(char *buffer, int size,
352 struct thread_entry *thread);
353#ifdef RB_PROFILE 288#ifdef RB_PROFILE
354void profile_thread(void); 289void profile_thread(void);
355#endif 290#endif
356 291
357#endif /* THREAD_H */ 292#endif /* THREAD_INTERNAL_H */