summaryrefslogtreecommitdiff
path: root/firmware/kernel/include/thread.h
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2014-04-24 04:09:18 -0400
committerMichael Sevakis <jethead71@rockbox.org>2014-08-06 02:47:47 +0200
commit533d396761b630e372166f6f0522ba1c2d128d70 (patch)
tree823a5f800049f62d4ea9f573b4cdeb3e7ff9b3e1 /firmware/kernel/include/thread.h
parent6536f1db3eedf0a12d16c5504cba94725eb6500d (diff)
downloadrockbox-533d396761b630e372166f6f0522ba1c2d128d70.tar.gz
rockbox-533d396761b630e372166f6f0522ba1c2d128d70.zip
Add multi-reader, single-writer locks to kernel.
Any number of readers may be in the critical section at a time and writers are mutually exclusive to all other threads. They are a better choice when data is rarely modified but often read and multiple threads can safely access it for reading. Priority inheritance is fully implemented along with other changes to the kernel to fully support it on multiowner objects. This also cleans up priority code in the kernel and updates some associated structures in existing objects to the cleaner form. Currently doesn't add the mrsw_lock.[ch] files since they're not yet needed by anything but the supporting improvements are still useful. This includes a typed bitarray API (bitarray.h) which is pretty basic for now. Change-Id: Idbe43dcd9170358e06d48d00f1c69728ff45b0e3 Reviewed-on: http://gerrit.rockbox.org/801 Reviewed-by: Michael Sevakis <jethead71@rockbox.org> Tested: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'firmware/kernel/include/thread.h')
-rw-r--r--firmware/kernel/include/thread.h81
1 files changed, 54 insertions, 27 deletions
diff --git a/firmware/kernel/include/thread.h b/firmware/kernel/include/thread.h
index 8c13b462e6..f181f867cb 100644
--- a/firmware/kernel/include/thread.h
+++ b/firmware/kernel/include/thread.h
@@ -28,6 +28,7 @@
28#include <stdbool.h> 28#include <stdbool.h>
29#include "gcc_extensions.h" 29#include "gcc_extensions.h"
30#include "corelock.h" 30#include "corelock.h"
31#include "bitarray.h"
31 32
32/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works 33/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works
33 * by giving high priority threads more CPU time than lower priority threads 34 * by giving high priority threads more CPU time than lower priority threads
@@ -80,6 +81,10 @@
80#endif 81#endif
81 82
82#define MAXTHREADS (BASETHREADS+TARGET_EXTRA_THREADS) 83#define MAXTHREADS (BASETHREADS+TARGET_EXTRA_THREADS)
84
85BITARRAY_TYPE_DECLARE(threadbit_t, threadbit, MAXTHREADS)
86BITARRAY_TYPE_DECLARE(priobit_t, priobit, NUM_PRIORITIES)
87
83/* 88/*
84 * We need more stack when we run under a host 89 * We need more stack when we run under a host
85 * maybe more expensive C lib functions? 90 * maybe more expensive C lib functions?
@@ -134,32 +139,39 @@ struct thread_list
134 struct thread_entry *next; /* Next thread in a list */ 139 struct thread_entry *next; /* Next thread in a list */
135}; 140};
136 141
137#ifdef HAVE_PRIORITY_SCHEDULING 142/* Basic structure describing the owner of an object */
138struct blocker 143struct blocker
139{ 144{
140 struct thread_entry * volatile thread; /* thread blocking other threads 145 struct thread_entry * volatile thread; /* thread blocking other threads
141 (aka. object owner) */ 146 (aka. object owner) */
142 int priority; /* highest priority waiter */ 147#ifdef HAVE_PRIORITY_SCHEDULING
143 struct thread_entry * (*wakeup_protocol)(struct thread_entry *thread); 148 int priority; /* highest priority waiter */
149#endif
144}; 150};
145 151
146/* Choices of wakeup protocol */ 152/* If a thread has a blocker but the blocker's registered thread is NULL,
147 153 then it references this and the struct blocker pointer may be
148/* For transfer of object ownership by one thread to another thread by 154 reinterpreted as such. */
149 * the owning thread itself (mutexes) */ 155struct blocker_splay
150struct thread_entry * 156{
151 wakeup_priority_protocol_transfer(struct thread_entry *thread); 157 struct blocker blocker; /* blocker info (first!) */
158#ifdef HAVE_PRIORITY_SCHEDULING
159 threadbit_t mask; /* mask of nonzero tcounts */
160#if NUM_CORES > 1
161 struct corelock cl; /* mutual exclusion */
162#endif
163#endif /* HAVE_PRIORITY_SCHEDULING */
164};
152 165
153/* For release by owner where ownership doesn't change - other threads, 166#ifdef HAVE_PRIORITY_SCHEDULING
154 * interrupts, timeouts, etc. (mutex timeout, queues) */
155struct thread_entry *
156 wakeup_priority_protocol_release(struct thread_entry *thread);
157 167
168/* Quick-disinherit of priority elevation. Must be a running thread. */
169void priority_disinherit(struct thread_entry *thread, struct blocker *bl);
158 170
159struct priority_distribution 171struct priority_distribution
160{ 172{
161 uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */ 173 uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */
162 uint32_t mask; /* Bitmask of hist entries that are not zero */ 174 priobit_t mask; /* Bitmask of hist entries that are not zero */
163}; 175};
164 176
165#endif /* HAVE_PRIORITY_SCHEDULING */ 177#endif /* HAVE_PRIORITY_SCHEDULING */
@@ -210,6 +222,7 @@ struct thread_entry
210 volatile intptr_t retval; /* Return value from a blocked operation/ 222 volatile intptr_t retval; /* Return value from a blocked operation/
211 misc. use */ 223 misc. use */
212#endif 224#endif
225 uint32_t id; /* Current slot id */
213 int __errno; /* Thread error number (errno tls) */ 226 int __errno; /* Thread error number (errno tls) */
214#ifdef HAVE_PRIORITY_SCHEDULING 227#ifdef HAVE_PRIORITY_SCHEDULING
215 /* Priority summary of owned objects that support inheritance */ 228 /* Priority summary of owned objects that support inheritance */
@@ -226,7 +239,6 @@ struct thread_entry
226 unsigned char priority; /* Scheduled priority (higher of base or 239 unsigned char priority; /* Scheduled priority (higher of base or
227 all threads blocked by this one) */ 240 all threads blocked by this one) */
228#endif 241#endif
229 uint16_t id; /* Current slot id */
230 unsigned short stack_size; /* Size of stack in bytes */ 242 unsigned short stack_size; /* Size of stack in bytes */
231 unsigned char state; /* Thread slot state (STATE_*) */ 243 unsigned char state; /* Thread slot state (STATE_*) */
232#ifdef HAVE_SCHEDULER_BOOSTCTRL 244#ifdef HAVE_SCHEDULER_BOOSTCTRL
@@ -238,11 +250,12 @@ struct thread_entry
238}; 250};
239 251
240/*** Macros for internal use ***/ 252/*** Macros for internal use ***/
241/* Thread ID, 16 bits = |VVVVVVVV|SSSSSSSS| */ 253/* Thread ID, 32 bits = |VVVVVVVV|VVVVVVVV|VVVVVVVV|SSSSSSSS| */
242#define THREAD_ID_VERSION_SHIFT 8 254#define THREAD_ID_VERSION_SHIFT 8
243#define THREAD_ID_VERSION_MASK 0xff00 255#define THREAD_ID_VERSION_MASK 0xffffff00
244#define THREAD_ID_SLOT_MASK 0x00ff 256#define THREAD_ID_SLOT_MASK 0x000000ff
245#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n)) 257#define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n))
258#define THREAD_ID_SLOT(id) ((id) & THREAD_ID_SLOT_MASK)
246 259
247#ifdef HAVE_CORELOCK_OBJECT 260#ifdef HAVE_CORELOCK_OBJECT
248/* Operations to be performed just before stopping a thread and starting 261/* Operations to be performed just before stopping a thread and starting
@@ -337,11 +350,8 @@ void switch_thread(void);
337/* Blocks a thread for at least the specified number of ticks (0 = wait until 350/* Blocks a thread for at least the specified number of ticks (0 = wait until
338 * next tick) */ 351 * next tick) */
339void sleep_thread(int ticks); 352void sleep_thread(int ticks);
340/* Indefinitely blocks the current thread on a thread queue */ 353/* Blocks the current thread on a thread queue (< 0 == infinite) */
341void block_thread(struct thread_entry *current); 354void block_thread(struct thread_entry *current, int timeout);
342/* Blocks the current thread on a thread queue until explicitely woken or
343 * the timeout is reached */
344void block_thread_w_tmo(struct thread_entry *current, int timeout);
345 355
346/* Return bit flags for thread wakeup */ 356/* Return bit flags for thread wakeup */
347#define THREAD_NONE 0x0 /* No thread woken up (exclusive) */ 357#define THREAD_NONE 0x0 /* No thread woken up (exclusive) */
@@ -350,15 +360,32 @@ void block_thread_w_tmo(struct thread_entry *current, int timeout);
350 higher priority than current were woken) */ 360 higher priority than current were woken) */
351 361
352/* A convenience function for waking an entire queue of threads. */ 362/* A convenience function for waking an entire queue of threads. */
353unsigned int thread_queue_wake(struct thread_entry **list); 363unsigned int thread_queue_wake(struct thread_entry **list,
364 volatile int *count);
354 365
355/* Wakeup a thread at the head of a list */ 366/* Wakeup a thread at the head of a list */
356unsigned int wakeup_thread(struct thread_entry **list); 367enum wakeup_thread_protocol
368{
369 WAKEUP_DEFAULT,
370 WAKEUP_TRANSFER,
371 WAKEUP_RELEASE,
372 WAKEUP_TRANSFER_MULTI,
373};
374
375unsigned int wakeup_thread_(struct thread_entry **list
376 IF_PRIO(, enum wakeup_thread_protocol proto));
357 377
358#ifdef HAVE_PRIORITY_SCHEDULING 378#ifdef HAVE_PRIORITY_SCHEDULING
379#define wakeup_thread(list, proto) \
380 wakeup_thread_((list), (proto))
381
359int thread_set_priority(unsigned int thread_id, int priority); 382int thread_set_priority(unsigned int thread_id, int priority);
360int thread_get_priority(unsigned int thread_id); 383int thread_get_priority(unsigned int thread_id);
384#else /* !HAVE_PRIORITY_SCHEDULING */
385#define wakeup_thread(list, proto...) \
386 wakeup_thread_((list));
361#endif /* HAVE_PRIORITY_SCHEDULING */ 387#endif /* HAVE_PRIORITY_SCHEDULING */
388
362#ifdef HAVE_IO_PRIORITY 389#ifdef HAVE_IO_PRIORITY
363void thread_set_io_priority(unsigned int thread_id, int io_priority); 390void thread_set_io_priority(unsigned int thread_id, int io_priority);
364int thread_get_io_priority(unsigned int thread_id); 391int thread_get_io_priority(unsigned int thread_id);