diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2014-04-24 04:09:18 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2014-08-06 02:47:47 +0200 |
commit | 533d396761b630e372166f6f0522ba1c2d128d70 (patch) | |
tree | 823a5f800049f62d4ea9f573b4cdeb3e7ff9b3e1 /firmware/kernel/include/thread.h | |
parent | 6536f1db3eedf0a12d16c5504cba94725eb6500d (diff) | |
download | rockbox-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.h | 81 |
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 | |||
85 | BITARRAY_TYPE_DECLARE(threadbit_t, threadbit, MAXTHREADS) | ||
86 | BITARRAY_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 */ |
138 | struct blocker | 143 | struct 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) */ | 155 | struct blocker_splay |
150 | struct 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) */ | ||
155 | struct thread_entry * | ||
156 | wakeup_priority_protocol_release(struct thread_entry *thread); | ||
157 | 167 | ||
168 | /* Quick-disinherit of priority elevation. Must be a running thread. */ | ||
169 | void priority_disinherit(struct thread_entry *thread, struct blocker *bl); | ||
158 | 170 | ||
159 | struct priority_distribution | 171 | struct 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) */ |
339 | void sleep_thread(int ticks); | 352 | void 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) */ |
341 | void block_thread(struct thread_entry *current); | 354 | void 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 */ | ||
344 | void 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. */ |
353 | unsigned int thread_queue_wake(struct thread_entry **list); | 363 | unsigned 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 */ |
356 | unsigned int wakeup_thread(struct thread_entry **list); | 367 | enum wakeup_thread_protocol |
368 | { | ||
369 | WAKEUP_DEFAULT, | ||
370 | WAKEUP_TRANSFER, | ||
371 | WAKEUP_RELEASE, | ||
372 | WAKEUP_TRANSFER_MULTI, | ||
373 | }; | ||
374 | |||
375 | unsigned 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 | |||
359 | int thread_set_priority(unsigned int thread_id, int priority); | 382 | int thread_set_priority(unsigned int thread_id, int priority); |
360 | int thread_get_priority(unsigned int thread_id); | 383 | int 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 |
363 | void thread_set_io_priority(unsigned int thread_id, int io_priority); | 390 | void thread_set_io_priority(unsigned int thread_id, int io_priority); |
364 | int thread_get_io_priority(unsigned int thread_id); | 391 | int thread_get_io_priority(unsigned int thread_id); |