diff options
Diffstat (limited to 'firmware/kernel/thread-internal.h')
-rw-r--r-- | firmware/kernel/thread-internal.h | 237 |
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 */ | ||
54 | struct corelock | ||
55 | { | ||
56 | volatile unsigned char myl[NUM_CORES]; | ||
57 | volatile unsigned char turn; | ||
58 | } __attribute__((packed)); | ||
59 | |||
60 | /* Too big to inline everywhere */ | ||
61 | void corelock_init(struct corelock *cl); | ||
62 | void corelock_lock(struct corelock *cl); | ||
63 | int corelock_try_lock(struct corelock *cl); | ||
64 | void 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. */ |
95 | struct thread_entry; /* forward */ | 71 | void priority_disinherit(struct thread_entry *thread, struct blocker *bl); |
96 | struct thread_list | 72 | |
73 | struct 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 |
111 | struct blocker | 82 | /* Operations to be performed just before stopping a thread and starting |
83 | a new one if specified before calling switch_thread */ | ||
84 | enum | ||
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 */ | 91 | struct thread_blk_ops |
120 | |||
121 | /* For transfer of object ownership by one thread to another thread by | ||
122 | * the owning thread itself (mutexes) */ | ||
123 | struct 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) */ | ||
128 | struct thread_entry * | ||
129 | wakeup_priority_protocol_release(struct thread_entry *thread); | ||
130 | |||
131 | |||
132 | struct 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 */ |
99 | struct thread_entry; /* forward */ | ||
100 | struct 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 */ | ||
222 | enum | ||
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 | |||
229 | struct 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 | |||
267 | void core_idle(void); | ||
268 | void core_wake(IF_COP_VOID(unsigned int core)); | ||
269 | |||
270 | /* Initialize the scheduler */ | ||
271 | void 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 |
275 | unsigned 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 | ||
283 | void trigger_cpu_boost(void); | ||
284 | void 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 */ | ||
290 | struct 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. */ | ||
293 | void thread_thaw(unsigned int thread_id); | ||
294 | /* Wait for a thread to exit */ | ||
295 | void thread_wait(unsigned int thread_id); | ||
296 | /* Exit the current thread */ | ||
297 | void 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 */ | ||
301 | void remove_thread(unsigned int thread_id); | ||
302 | #endif | ||
303 | 233 | ||
304 | /* Switch to next runnable thread */ | 234 | /* Switch to next runnable thread */ |
305 | void switch_thread(void); | 235 | void 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) */ |
308 | void sleep_thread(int ticks); | 238 | void 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) */ |
310 | void block_thread(struct thread_entry *current); | 240 | void 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 */ | ||
313 | void 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); | |||
322 | unsigned int thread_queue_wake(struct thread_entry **list); | 249 | unsigned 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 */ |
325 | unsigned int wakeup_thread(struct thread_entry **list); | 252 | enum wakeup_thread_protocol |
253 | { | ||
254 | WAKEUP_DEFAULT, | ||
255 | WAKEUP_TRANSFER, | ||
256 | WAKEUP_RELEASE, | ||
257 | WAKEUP_TRANSFER_MULTI, | ||
258 | }; | ||
259 | |||
260 | unsigned 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 |
328 | int thread_set_priority(unsigned int thread_id, int priority); | 264 | #define wakeup_thread(list, proto) \ |
329 | int 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 |
332 | void thread_set_io_priority(unsigned int thread_id, int io_priority); | 272 | void thread_set_io_priority(unsigned int thread_id, int io_priority); |
333 | int thread_get_io_priority(unsigned int thread_id); | 273 | int 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. */ |
340 | unsigned int thread_self(void); | 280 | unsigned 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. */ | ||
344 | struct thread_entry* thread_self_entry(void); | 283 | struct thread_entry* thread_self_entry(void); |
345 | 284 | ||
346 | /* Debugging info - only! */ | 285 | /* Return thread entry from id */ |
347 | int thread_stack_usage(const struct thread_entry *thread); | 286 | struct thread_entry *thread_id_entry(unsigned int thread_id); |
348 | #if NUM_CORES > 1 | 287 | |
349 | int idle_stack_usage(unsigned int core); | ||
350 | #endif | ||
351 | void thread_get_name(char *buffer, int size, | ||
352 | struct thread_entry *thread); | ||
353 | #ifdef RB_PROFILE | 288 | #ifdef RB_PROFILE |
354 | void profile_thread(void); | 289 | void profile_thread(void); |
355 | #endif | 290 | #endif |
356 | 291 | ||
357 | #endif /* THREAD_H */ | 292 | #endif /* THREAD_INTERNAL_H */ |