diff options
Diffstat (limited to 'firmware/thread.c')
-rw-r--r-- | firmware/thread.c | 170 |
1 files changed, 111 insertions, 59 deletions
diff --git a/firmware/thread.c b/firmware/thread.c index 0013d49519..c194b2694d 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -41,7 +41,7 @@ struct regs | |||
41 | void *pr; /* Procedure register */ | 41 | void *pr; /* Procedure register */ |
42 | void *start; /* Thread start address, or NULL when started */ | 42 | void *start; /* Thread start address, or NULL when started */ |
43 | }; | 43 | }; |
44 | #elif defined(CPU_ARM) | 44 | #elif defined(CPU_ARM) |
45 | struct regs | 45 | struct regs |
46 | { | 46 | { |
47 | unsigned int r[8]; /* Registers r4-r11 */ | 47 | unsigned int r[8]; /* Registers r4-r11 */ |
@@ -62,18 +62,31 @@ struct regs | |||
62 | /* Cast to the the machine int type, whose size could be < 4. */ | 62 | /* Cast to the the machine int type, whose size could be < 4. */ |
63 | 63 | ||
64 | 64 | ||
65 | int num_threads; | 65 | int num_threads[NUM_CORES]; |
66 | static volatile int num_sleepers; | 66 | static volatile int num_sleepers[NUM_CORES]; |
67 | static int current_thread; | 67 | static int current_thread[NUM_CORES]; |
68 | static struct regs thread_contexts[MAXTHREADS] IBSS_ATTR; | 68 | static struct regs thread_contexts[NUM_CORES][MAXTHREADS] IBSS_ATTR; |
69 | const char *thread_name[MAXTHREADS]; | 69 | const char *thread_name[NUM_CORES][MAXTHREADS]; |
70 | void *thread_stack[MAXTHREADS]; | 70 | void *thread_stack[NUM_CORES][MAXTHREADS]; |
71 | int thread_stack_size[MAXTHREADS]; | 71 | int thread_stack_size[NUM_CORES][MAXTHREADS]; |
72 | static const char main_thread_name[] = "main"; | 72 | static const char main_thread_name[] = "main"; |
73 | 73 | ||
74 | extern int stackbegin[]; | 74 | extern int stackbegin[]; |
75 | extern int stackend[]; | 75 | extern int stackend[]; |
76 | 76 | ||
77 | #ifdef CPU_PP | ||
78 | #ifndef BOOTLOADER | ||
79 | extern int cop_stackbegin[]; | ||
80 | extern int cop_stackend[]; | ||
81 | #else | ||
82 | /* The coprocessor stack is not set up in the bootloader code, but the | ||
83 | threading is. No threads are run on the coprocessor, so set up some dummy | ||
84 | stack */ | ||
85 | int *cop_stackbegin = stackbegin; | ||
86 | int *cop_stackend = stackend; | ||
87 | #endif | ||
88 | #endif | ||
89 | |||
77 | void switch_thread(void) ICODE_ATTR; | 90 | void switch_thread(void) ICODE_ATTR; |
78 | static inline void store_context(void* addr) __attribute__ ((always_inline)); | 91 | static inline void store_context(void* addr) __attribute__ ((always_inline)); |
79 | static inline void load_context(const void* addr) __attribute__ ((always_inline)); | 92 | static inline void load_context(const void* addr) __attribute__ ((always_inline)); |
@@ -86,7 +99,7 @@ void profile_thread(void) { | |||
86 | #endif | 99 | #endif |
87 | 100 | ||
88 | #if defined(CPU_ARM) | 101 | #if defined(CPU_ARM) |
89 | /*--------------------------------------------------------------------------- | 102 | /*--------------------------------------------------------------------------- |
90 | * Store non-volatile context. | 103 | * Store non-volatile context. |
91 | *--------------------------------------------------------------------------- | 104 | *--------------------------------------------------------------------------- |
92 | */ | 105 | */ |
@@ -116,7 +129,7 @@ static inline void load_context(const void* addr) | |||
116 | } | 129 | } |
117 | 130 | ||
118 | #elif defined(CPU_COLDFIRE) | 131 | #elif defined(CPU_COLDFIRE) |
119 | /*--------------------------------------------------------------------------- | 132 | /*--------------------------------------------------------------------------- |
120 | * Store non-volatile context. | 133 | * Store non-volatile context. |
121 | *--------------------------------------------------------------------------- | 134 | *--------------------------------------------------------------------------- |
122 | */ | 135 | */ |
@@ -199,7 +212,7 @@ static inline void load_context(const void* addr) | |||
199 | } | 212 | } |
200 | 213 | ||
201 | #elif CONFIG_CPU == TCC730 | 214 | #elif CONFIG_CPU == TCC730 |
202 | /*--------------------------------------------------------------------------- | 215 | /*--------------------------------------------------------------------------- |
203 | * Store non-volatile context. | 216 | * Store non-volatile context. |
204 | *--------------------------------------------------------------------------- | 217 | *--------------------------------------------------------------------------- |
205 | */ | 218 | */ |
@@ -215,7 +228,7 @@ static inline void load_context(const void* addr) | |||
215 | "push a14\n\t" \ | 228 | "push a14\n\t" \ |
216 | "ldw @[%0+0], a15\n\t" : : "a" (addr) ); | 229 | "ldw @[%0+0], a15\n\t" : : "a" (addr) ); |
217 | 230 | ||
218 | /*--------------------------------------------------------------------------- | 231 | /*--------------------------------------------------------------------------- |
219 | * Load non-volatile context. | 232 | * Load non-volatile context. |
220 | *--------------------------------------------------------------------------- | 233 | *--------------------------------------------------------------------------- |
221 | */ | 234 | */ |
@@ -260,7 +273,7 @@ void switch_thread(void) | |||
260 | #ifdef SIMULATOR | 273 | #ifdef SIMULATOR |
261 | /* Do nothing */ | 274 | /* Do nothing */ |
262 | #else | 275 | #else |
263 | while (num_sleepers == num_threads) | 276 | while (num_sleepers[CURRENT_CORE] == num_threads[CURRENT_CORE]) |
264 | { | 277 | { |
265 | /* Enter sleep mode, woken up on interrupt */ | 278 | /* Enter sleep mode, woken up on interrupt */ |
266 | #ifdef CPU_COLDFIRE | 279 | #ifdef CPU_COLDFIRE |
@@ -284,21 +297,21 @@ void switch_thread(void) | |||
284 | #endif | 297 | #endif |
285 | } | 298 | } |
286 | #endif | 299 | #endif |
287 | current = current_thread; | 300 | current = current_thread[CURRENT_CORE]; |
288 | store_context(&thread_contexts[current]); | 301 | store_context(&thread_contexts[CURRENT_CORE][current]); |
289 | 302 | ||
290 | #if CONFIG_CPU != TCC730 | 303 | #if CONFIG_CPU != TCC730 |
291 | /* Check if the current thread stack is overflown */ | 304 | /* Check if the current thread stack is overflown */ |
292 | stackptr = thread_stack[current]; | 305 | stackptr = thread_stack[CURRENT_CORE][current]; |
293 | if(stackptr[0] != DEADBEEF) | 306 | if(stackptr[0] != DEADBEEF) |
294 | panicf("Stkov %s", thread_name[current]); | 307 | panicf("Stkov %s", thread_name[CURRENT_CORE][current]); |
295 | #endif | 308 | #endif |
296 | 309 | ||
297 | if (++current >= num_threads) | 310 | if (++current >= num_threads[CURRENT_CORE]) |
298 | current = 0; | 311 | current = 0; |
299 | 312 | ||
300 | current_thread = current; | 313 | current_thread[CURRENT_CORE] = current; |
301 | load_context(&thread_contexts[current]); | 314 | load_context(&thread_contexts[CURRENT_CORE][current]); |
302 | #ifdef RB_PROFILE | 315 | #ifdef RB_PROFILE |
303 | profile_thread_started(current_thread); | 316 | profile_thread_started(current_thread); |
304 | #endif | 317 | #endif |
@@ -306,29 +319,42 @@ void switch_thread(void) | |||
306 | 319 | ||
307 | void sleep_thread(void) | 320 | void sleep_thread(void) |
308 | { | 321 | { |
309 | ++num_sleepers; | 322 | ++num_sleepers[CURRENT_CORE]; |
310 | switch_thread(); | 323 | switch_thread(); |
311 | } | 324 | } |
312 | 325 | ||
313 | void wake_up_thread(void) | 326 | void wake_up_thread(void) |
314 | { | 327 | { |
315 | num_sleepers = 0; | 328 | num_sleepers[CURRENT_CORE] = 0; |
316 | } | 329 | } |
317 | 330 | ||
318 | /*--------------------------------------------------------------------------- | 331 | |
319 | * Create thread. | 332 | /*--------------------------------------------------------------------------- |
333 | * Create thread on the current core. | ||
320 | * Return ID if context area could be allocated, else -1. | 334 | * Return ID if context area could be allocated, else -1. |
321 | *--------------------------------------------------------------------------- | 335 | *--------------------------------------------------------------------------- |
322 | */ | 336 | */ |
323 | int create_thread(void (*function)(void), void* stack, int stack_size, | 337 | int create_thread(void (*function)(void), void* stack, int stack_size, |
324 | const char *name) | 338 | const char *name) |
325 | { | 339 | { |
340 | return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, | ||
341 | name); | ||
342 | } | ||
343 | |||
344 | /*--------------------------------------------------------------------------- | ||
345 | * Create thread on a specific core. | ||
346 | * Return ID if context area could be allocated, else -1. | ||
347 | *--------------------------------------------------------------------------- | ||
348 | */ | ||
349 | int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, | ||
350 | const char *name) | ||
351 | { | ||
326 | unsigned int i; | 352 | unsigned int i; |
327 | unsigned int stacklen; | 353 | unsigned int stacklen; |
328 | unsigned int *stackptr; | 354 | unsigned int *stackptr; |
329 | struct regs *regs; | 355 | struct regs *regs; |
330 | 356 | ||
331 | if (num_threads >= MAXTHREADS) | 357 | if (num_threads[core] >= MAXTHREADS) |
332 | return -1; | 358 | return -1; |
333 | 359 | ||
334 | /* Munge the stack to make it easy to spot stack overflows */ | 360 | /* Munge the stack to make it easy to spot stack overflows */ |
@@ -340,10 +366,10 @@ int create_thread(void (*function)(void), void* stack, int stack_size, | |||
340 | } | 366 | } |
341 | 367 | ||
342 | /* Store interesting information */ | 368 | /* Store interesting information */ |
343 | thread_name[num_threads] = name; | 369 | thread_name[core][num_threads[core]] = name; |
344 | thread_stack[num_threads] = stack; | 370 | thread_stack[core][num_threads[core]] = stack; |
345 | thread_stack_size[num_threads] = stack_size; | 371 | thread_stack_size[core][num_threads[core]] = stack_size; |
346 | regs = &thread_contexts[num_threads]; | 372 | regs = &thread_contexts[core][num_threads[core]]; |
347 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) | 373 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) |
348 | /* Align stack to an even 32 bit boundary */ | 374 | /* Align stack to an even 32 bit boundary */ |
349 | regs->sp = (void*)(((unsigned int)stack + stack_size) & ~3); | 375 | regs->sp = (void*)(((unsigned int)stack + stack_size) & ~3); |
@@ -355,65 +381,91 @@ int create_thread(void (*function)(void), void* stack, int stack_size, | |||
355 | regs->start = (void*)function; | 381 | regs->start = (void*)function; |
356 | 382 | ||
357 | wake_up_thread(); | 383 | wake_up_thread(); |
358 | return num_threads++; /* return the current ID, e.g for remove_thread() */ | 384 | return num_threads[core]++; /* return the current ID, e.g for remove_thread() */ |
359 | } | 385 | } |
360 | 386 | ||
361 | /*--------------------------------------------------------------------------- | 387 | /*--------------------------------------------------------------------------- |
362 | * Remove a thread from the scheduler. | 388 | * Remove a thread on the current core from the scheduler. |
363 | * Parameter is the ID as returned from create_thread(). | 389 | * Parameter is the ID as returned from create_thread(). |
364 | *--------------------------------------------------------------------------- | 390 | *--------------------------------------------------------------------------- |
365 | */ | 391 | */ |
366 | void remove_thread(int threadnum) | 392 | void remove_thread(int threadnum) |
367 | { | 393 | { |
394 | remove_thread_on_core(CURRENT_CORE, threadnum); | ||
395 | } | ||
396 | |||
397 | /*--------------------------------------------------------------------------- | ||
398 | * Remove a thread on the specified core from the scheduler. | ||
399 | * Parameters are the core and the ID as returned from create_thread(). | ||
400 | *--------------------------------------------------------------------------- | ||
401 | */ | ||
402 | void remove_thread_on_core(unsigned int core, int threadnum) | ||
403 | { | ||
368 | int i; | 404 | int i; |
369 | 405 | ||
370 | if(threadnum >= num_threads) | 406 | if(threadnum >= num_threads[core]) |
371 | return; | 407 | return; |
372 | 408 | ||
373 | num_threads--; | 409 | num_threads[core]--; |
374 | for (i=threadnum; i<num_threads-1; i++) | 410 | for (i=threadnum; i<num_threads[core]-1; i++) |
375 | { /* move all entries which are behind */ | 411 | { /* move all entries which are behind */ |
376 | thread_name[i] = thread_name[i+1]; | 412 | thread_name[core][i] = thread_name[core][i+1]; |
377 | thread_stack[i] = thread_stack[i+1]; | 413 | thread_stack[core][i] = thread_stack[core][i+1]; |
378 | thread_stack_size[i] = thread_stack_size[i+1]; | 414 | thread_stack_size[core][i] = thread_stack_size[core][i+1]; |
379 | thread_contexts[i] = thread_contexts[i+1]; | 415 | thread_contexts[core][i] = thread_contexts[core][i+1]; |
380 | } | 416 | } |
381 | 417 | ||
382 | if (current_thread == threadnum) /* deleting the current one? */ | 418 | if (current_thread[core] == threadnum) /* deleting the current one? */ |
383 | current_thread = num_threads; /* set beyond last, avoid store harm */ | 419 | current_thread[core] = num_threads[core]; /* set beyond last, avoid store harm */ |
384 | else if (current_thread > threadnum) /* within the moved positions? */ | 420 | else if (current_thread[core] > threadnum) /* within the moved positions? */ |
385 | current_thread--; /* adjust it, point to same context again */ | 421 | current_thread[core]--; /* adjust it, point to same context again */ |
386 | } | 422 | } |
387 | 423 | ||
388 | void init_threads(void) | 424 | void init_threads(void) |
389 | { | 425 | { |
390 | num_threads = 1; /* We have 1 thread to begin with */ | 426 | unsigned int core = CURRENT_CORE; |
391 | current_thread = 0; /* The current thread is number 0 */ | 427 | |
392 | thread_name[0] = main_thread_name; | 428 | num_threads[core] = 1; /* We have 1 thread to begin with */ |
393 | thread_stack[0] = stackbegin; | 429 | current_thread[core] = 0; /* The current thread is number 0 */ |
394 | thread_stack_size[0] = (int)stackend - (int)stackbegin; | 430 | thread_name[core][0] = main_thread_name; |
431 | /* In multiple core setups, each core has a different stack. There is probably | ||
432 | a much better way to do this. */ | ||
433 | if(core == CPU) | ||
434 | { | ||
435 | thread_stack[CPU][0] = stackbegin; | ||
436 | thread_stack_size[CPU][0] = (int)stackend - (int)stackbegin; | ||
437 | } else { | ||
438 | #if NUM_CORES > 1 /* This code path will not be run on single core targets */ | ||
439 | thread_stack[COP][0] = cop_stackbegin; | ||
440 | thread_stack_size[COP][0] = (int)cop_stackend - (int)cop_stackbegin; | ||
441 | #endif | ||
442 | } | ||
395 | #if CONFIG_CPU == TCC730 | 443 | #if CONFIG_CPU == TCC730 |
396 | thread_contexts[0].started = 1; | 444 | thread_contexts[core][0].started = 1; |
397 | #else | 445 | #else |
398 | thread_contexts[0].start = 0; /* thread 0 already running */ | 446 | thread_contexts[core][0].start = 0; /* thread 0 already running */ |
399 | #endif | 447 | #endif |
400 | num_sleepers = 0; | 448 | num_sleepers[core] = 0; |
449 | } | ||
450 | |||
451 | int thread_stack_usage(int threadnum){ | ||
452 | return thread_stack_usage_on_core(CURRENT_CORE, threadnum); | ||
401 | } | 453 | } |
402 | 454 | ||
403 | int thread_stack_usage(int threadnum) | 455 | int thread_stack_usage_on_core(unsigned int core, int threadnum) |
404 | { | 456 | { |
405 | unsigned int i; | 457 | unsigned int i; |
406 | unsigned int *stackptr = thread_stack[threadnum]; | 458 | unsigned int *stackptr = thread_stack[core][threadnum]; |
407 | 459 | ||
408 | if(threadnum >= num_threads) | 460 | if(threadnum >= num_threads[core]) |
409 | return -1; | 461 | return -1; |
410 | 462 | ||
411 | for(i = 0;i < thread_stack_size[threadnum]/sizeof(int);i++) | 463 | for(i = 0;i < thread_stack_size[core][threadnum]/sizeof(int);i++) |
412 | { | 464 | { |
413 | if(stackptr[i] != DEADBEEF) | 465 | if(stackptr[i] != DEADBEEF) |
414 | break; | 466 | break; |
415 | } | 467 | } |
416 | 468 | ||
417 | return ((thread_stack_size[threadnum] - i * sizeof(int)) * 100) / | 469 | return ((thread_stack_size[core][threadnum] - i * sizeof(int)) * 100) / |
418 | thread_stack_size[threadnum]; | 470 | thread_stack_size[core][threadnum]; |
419 | } | 471 | } |