summaryrefslogtreecommitdiff
path: root/firmware/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/thread.c')
-rw-r--r--firmware/thread.c170
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)
45struct regs 45struct 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
65int num_threads; 65int num_threads[NUM_CORES];
66static volatile int num_sleepers; 66static volatile int num_sleepers[NUM_CORES];
67static int current_thread; 67static int current_thread[NUM_CORES];
68static struct regs thread_contexts[MAXTHREADS] IBSS_ATTR; 68static struct regs thread_contexts[NUM_CORES][MAXTHREADS] IBSS_ATTR;
69const char *thread_name[MAXTHREADS]; 69const char *thread_name[NUM_CORES][MAXTHREADS];
70void *thread_stack[MAXTHREADS]; 70void *thread_stack[NUM_CORES][MAXTHREADS];
71int thread_stack_size[MAXTHREADS]; 71int thread_stack_size[NUM_CORES][MAXTHREADS];
72static const char main_thread_name[] = "main"; 72static const char main_thread_name[] = "main";
73 73
74extern int stackbegin[]; 74extern int stackbegin[];
75extern int stackend[]; 75extern int stackend[];
76 76
77#ifdef CPU_PP
78#ifndef BOOTLOADER
79extern int cop_stackbegin[];
80extern 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 */
85int *cop_stackbegin = stackbegin;
86int *cop_stackend = stackend;
87#endif
88#endif
89
77void switch_thread(void) ICODE_ATTR; 90void switch_thread(void) ICODE_ATTR;
78static inline void store_context(void* addr) __attribute__ ((always_inline)); 91static inline void store_context(void* addr) __attribute__ ((always_inline));
79static inline void load_context(const void* addr) __attribute__ ((always_inline)); 92static 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
307void sleep_thread(void) 320void sleep_thread(void)
308{ 321{
309 ++num_sleepers; 322 ++num_sleepers[CURRENT_CORE];
310 switch_thread(); 323 switch_thread();
311} 324}
312 325
313void wake_up_thread(void) 326void 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 */
323int create_thread(void (*function)(void), void* stack, int stack_size, 337int 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 */
349int 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 */
366void remove_thread(int threadnum) 392void 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 */
402void 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
388void init_threads(void) 424void 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
451int thread_stack_usage(int threadnum){
452 return thread_stack_usage_on_core(CURRENT_CORE, threadnum);
401} 453}
402 454
403int thread_stack_usage(int threadnum) 455int 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}