diff options
Diffstat (limited to 'firmware/thread.c')
-rw-r--r-- | firmware/thread.c | 485 |
1 files changed, 397 insertions, 88 deletions
diff --git a/firmware/thread.c b/firmware/thread.c index eb39c7ad32..e4dcbbcf9a 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -23,12 +23,18 @@ | |||
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "kernel.h" | 24 | #include "kernel.h" |
25 | #include "cpu.h" | 25 | #include "cpu.h" |
26 | 26 | #include "string.h" | |
27 | 27 | ||
28 | #define DEADBEEF ((unsigned int)0xdeadbeef) | 28 | #define DEADBEEF ((unsigned int)0xdeadbeef) |
29 | /* Cast to the the machine int type, whose size could be < 4. */ | 29 | /* Cast to the the machine int type, whose size could be < 4. */ |
30 | 30 | ||
31 | struct core_entry cores[NUM_CORES] IBSS_ATTR; | 31 | struct core_entry cores[NUM_CORES] IBSS_ATTR; |
32 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
33 | static unsigned short highest_priority IBSS_ATTR; | ||
34 | #endif | ||
35 | |||
36 | /* Define to enable additional checks for blocking violations etc. */ | ||
37 | // #define THREAD_EXTRA_CHECKS | ||
32 | 38 | ||
33 | static const char main_thread_name[] = "main"; | 39 | static const char main_thread_name[] = "main"; |
34 | 40 | ||
@@ -48,7 +54,16 @@ int *cop_stackend = stackend; | |||
48 | #endif | 54 | #endif |
49 | #endif | 55 | #endif |
50 | 56 | ||
51 | void switch_thread(void) ICODE_ATTR; | 57 | /* Conserve IRAM |
58 | static void add_to_list(struct thread_entry **list, | ||
59 | struct thread_entry *thread) ICODE_ATTR; | ||
60 | static void remove_from_list(struct thread_entry **list, | ||
61 | struct thread_entry *thread) ICODE_ATTR; | ||
62 | */ | ||
63 | |||
64 | void switch_thread(bool save_context, struct thread_entry **blocked_list) | ||
65 | ICODE_ATTR; | ||
66 | |||
52 | static inline void store_context(void* addr) __attribute__ ((always_inline)); | 67 | static inline void store_context(void* addr) __attribute__ ((always_inline)); |
53 | static inline void load_context(const void* addr) __attribute__ ((always_inline)); | 68 | static inline void load_context(const void* addr) __attribute__ ((always_inline)); |
54 | 69 | ||
@@ -219,24 +234,109 @@ static inline void load_context(const void* addr) | |||
219 | 234 | ||
220 | #endif | 235 | #endif |
221 | 236 | ||
222 | /*--------------------------------------------------------------------------- | 237 | static void add_to_list(struct thread_entry **list, |
223 | * Switch thread in round robin fashion. | 238 | struct thread_entry *thread) |
224 | *--------------------------------------------------------------------------- | ||
225 | */ | ||
226 | void switch_thread(void) | ||
227 | { | 239 | { |
228 | #ifdef RB_PROFILE | 240 | if (*list == NULL) |
229 | profile_thread_stopped(cores[CURRENT_CORE].current_thread); | 241 | { |
230 | #endif | 242 | thread->next = thread; |
231 | int current; | 243 | thread->prev = thread; |
232 | unsigned int *stackptr; | 244 | *list = thread; |
245 | } | ||
246 | else | ||
247 | { | ||
248 | /* Insert last */ | ||
249 | thread->next = *list; | ||
250 | thread->prev = (*list)->prev; | ||
251 | thread->prev->next = thread; | ||
252 | (*list)->prev = thread; | ||
253 | |||
254 | /* Insert next | ||
255 | thread->next = (*list)->next; | ||
256 | thread->prev = *list; | ||
257 | thread->next->prev = thread; | ||
258 | (*list)->next = thread; | ||
259 | */ | ||
260 | } | ||
261 | } | ||
233 | 262 | ||
234 | #ifdef SIMULATOR | 263 | static void remove_from_list(struct thread_entry **list, |
235 | /* Do nothing */ | 264 | struct thread_entry *thread) |
236 | #else | 265 | { |
237 | while (cores[CURRENT_CORE].num_sleepers == cores[CURRENT_CORE].num_threads) | 266 | if (list != NULL) |
267 | { | ||
268 | if (thread == thread->next) | ||
269 | { | ||
270 | *list = NULL; | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | if (thread == *list) | ||
275 | *list = thread->next; | ||
276 | } | ||
277 | |||
278 | /* Fix links to jump over the removed entry. */ | ||
279 | thread->prev->next = thread->next; | ||
280 | thread->next->prev = thread->prev; | ||
281 | } | ||
282 | |||
283 | /* Compiler trick: Don't declare as static to prevent putting | ||
284 | * function in IRAM. */ | ||
285 | void check_sleepers(void) | ||
286 | { | ||
287 | struct thread_entry *current, *next; | ||
288 | |||
289 | /* Check sleeping threads. */ | ||
290 | current = cores[CURRENT_CORE].sleeping; | ||
291 | if (current == NULL) | ||
292 | return ; | ||
293 | |||
294 | for (;;) | ||
295 | { | ||
296 | next = current->next; | ||
297 | |||
298 | if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg)) | ||
299 | { | ||
300 | /* Sleep timeout has been reached so bring the thread | ||
301 | * back to life again. */ | ||
302 | remove_from_list(&cores[CURRENT_CORE].sleeping, current); | ||
303 | add_to_list(&cores[CURRENT_CORE].running, current); | ||
304 | |||
305 | /* If there is no more processes in the list, break the loop. */ | ||
306 | if (cores[CURRENT_CORE].sleeping == NULL) | ||
307 | break; | ||
308 | |||
309 | current = next; | ||
310 | continue; | ||
311 | } | ||
312 | |||
313 | current = next; | ||
314 | |||
315 | /* Break the loop once we have walked through the list of all | ||
316 | * sleeping processes. */ | ||
317 | if (current == cores[CURRENT_CORE].sleeping) | ||
318 | break; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | static inline void sleep_core(void) | ||
323 | { | ||
324 | static long last_tick = 0; | ||
325 | |||
326 | for (;;) | ||
238 | { | 327 | { |
239 | /* Enter sleep mode, woken up on interrupt */ | 328 | if (last_tick != current_tick) |
329 | { | ||
330 | check_sleepers(); | ||
331 | last_tick = current_tick; | ||
332 | } | ||
333 | |||
334 | /* We must sleep until there is at least one process in the list | ||
335 | * of running processes. */ | ||
336 | if (cores[CURRENT_CORE].running != NULL) | ||
337 | break; | ||
338 | |||
339 | /* Enter sleep mode to reduce power usage, woken up on interrupt */ | ||
240 | #ifdef CPU_COLDFIRE | 340 | #ifdef CPU_COLDFIRE |
241 | asm volatile ("stop #0x2000"); | 341 | asm volatile ("stop #0x2000"); |
242 | #elif CONFIG_CPU == SH7034 | 342 | #elif CONFIG_CPU == SH7034 |
@@ -257,49 +357,232 @@ void switch_thread(void) | |||
257 | CLKCON |= 2; | 357 | CLKCON |= 2; |
258 | #endif | 358 | #endif |
259 | } | 359 | } |
260 | #endif | 360 | } |
261 | current = cores[CURRENT_CORE].current_thread; | 361 | |
262 | store_context(&cores[CURRENT_CORE].threads[current].context); | 362 | #ifdef RB_PROFILE |
263 | 363 | static int get_threadnum(struct thread_entry *thread) | |
264 | #if CONFIG_CPU != TCC730 | 364 | { |
265 | /* Check if the current thread stack is overflown */ | 365 | int i; |
266 | stackptr = cores[CURRENT_CORE].threads[current].stack; | 366 | |
267 | if(stackptr[0] != DEADBEEF) | 367 | for (i = 0; i < MAXTHREADS; i++) |
268 | panicf("Stkov %s", cores[CURRENT_CORE].threads[current].name); | 368 | { |
369 | if (&cores[CURRENT_CORE].threads[i] == thread) | ||
370 | return i; | ||
371 | } | ||
372 | |||
373 | return -1; | ||
374 | } | ||
269 | #endif | 375 | #endif |
270 | 376 | ||
271 | if (++current >= cores[CURRENT_CORE].num_threads) | 377 | /* Compiler trick: Don't declare as static to prevent putting |
272 | current = 0; | 378 | * function in IRAM. */ |
379 | void change_thread_state(struct thread_entry **blocked_list) | ||
380 | { | ||
381 | struct thread_entry *old; | ||
382 | |||
383 | /* Remove the thread from the list of running threads. */ | ||
384 | old = cores[CURRENT_CORE].running; | ||
385 | remove_from_list(&cores[CURRENT_CORE].running, old); | ||
386 | |||
387 | /* And put the thread into a new list of inactive threads. */ | ||
388 | if (GET_STATE(old->statearg) == STATE_BLOCKED) | ||
389 | add_to_list(blocked_list, old); | ||
390 | else | ||
391 | add_to_list(&cores[CURRENT_CORE].sleeping, old); | ||
392 | |||
393 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
394 | /* Reset priorities */ | ||
395 | if (old->priority == highest_priority) | ||
396 | highest_priority = 100; | ||
397 | #endif | ||
398 | } | ||
273 | 399 | ||
274 | cores[CURRENT_CORE].current_thread = current; | 400 | /*--------------------------------------------------------------------------- |
275 | load_context(&cores[CURRENT_CORE].threads[current].context); | 401 | * Switch thread in round robin fashion. |
402 | *--------------------------------------------------------------------------- | ||
403 | */ | ||
404 | void switch_thread(bool save_context, struct thread_entry **blocked_list) | ||
405 | { | ||
276 | #ifdef RB_PROFILE | 406 | #ifdef RB_PROFILE |
277 | profile_thread_started(cores[CURRENT_CORE].current_thread); | 407 | profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running)); |
408 | #endif | ||
409 | unsigned int *stackptr; | ||
410 | |||
411 | #ifdef SIMULATOR | ||
412 | /* Do nothing */ | ||
413 | #else | ||
414 | |||
415 | /* Begin task switching by saving our current context so that we can | ||
416 | * restore the state of the current thread later to the point prior | ||
417 | * to this call. */ | ||
418 | if (save_context) | ||
419 | { | ||
420 | store_context(&cores[CURRENT_CORE].running->context); | ||
421 | |||
422 | # if CONFIG_CPU != TCC730 | ||
423 | /* Check if the current thread stack is overflown */ | ||
424 | stackptr = cores[CURRENT_CORE].running->stack; | ||
425 | if(stackptr[0] != DEADBEEF) | ||
426 | panicf("Stkov %s", cores[CURRENT_CORE].running->name); | ||
427 | # endif | ||
428 | |||
429 | /* Check if a thread state change has been requested. */ | ||
430 | if (cores[CURRENT_CORE].running->statearg) | ||
431 | { | ||
432 | /* Change running thread state and switch to next thread. */ | ||
433 | change_thread_state(blocked_list); | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | /* Switch to the next running thread. */ | ||
438 | cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | /* Go through the list of sleeping task to check if we need to wake up | ||
443 | * any of them due to timeout. Also puts core into sleep state until | ||
444 | * there is at least one running process again. */ | ||
445 | sleep_core(); | ||
446 | |||
447 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
448 | /* Select the new task based on priorities and the last time a process | ||
449 | * got CPU time. */ | ||
450 | for (;;) | ||
451 | { | ||
452 | int priority = cores[CURRENT_CORE].running->priority; | ||
453 | |||
454 | if (priority < highest_priority) | ||
455 | highest_priority = priority; | ||
456 | |||
457 | if (priority == highest_priority || (current_tick | ||
458 | - cores[CURRENT_CORE].running->last_run > priority * 8)) | ||
459 | { | ||
460 | break; | ||
461 | } | ||
462 | cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next; | ||
463 | } | ||
464 | |||
465 | /* Reset the value of thread's last running time to the current time. */ | ||
466 | cores[CURRENT_CORE].running->last_run = current_tick; | ||
467 | #endif | ||
468 | |||
469 | #endif | ||
470 | /* And finally give control to the next thread. */ | ||
471 | load_context(&cores[CURRENT_CORE].running->context); | ||
472 | |||
473 | #ifdef RB_PROFILE | ||
474 | profile_thread_started(get_threadnum(cores[CURRENT_CORE].running)); | ||
278 | #endif | 475 | #endif |
279 | } | 476 | } |
280 | 477 | ||
281 | void sleep_thread(void) | 478 | void sleep_thread(int ticks) |
282 | { | 479 | { |
283 | ++cores[CURRENT_CORE].num_sleepers; | 480 | /* Set the thread's new state and timeout and finally force a task switch |
284 | switch_thread(); | 481 | * so that scheduler removes thread from the list of running processes |
482 | * and puts it in list of sleeping tasks. */ | ||
483 | cores[CURRENT_CORE].running->statearg = | ||
484 | SET_STATE(STATE_SLEEPING, current_tick + ticks + 1); | ||
485 | switch_thread(true, NULL); | ||
486 | |||
487 | /* Clear all flags to indicate we are up and running again. */ | ||
488 | cores[CURRENT_CORE].running->statearg = 0; | ||
285 | } | 489 | } |
286 | 490 | ||
287 | void wake_up_thread(void) | 491 | void block_thread(struct thread_entry **list, int timeout) |
288 | { | 492 | { |
289 | cores[CURRENT_CORE].num_sleepers = 0; | 493 | struct thread_entry *current; |
494 | |||
495 | /* Get the entry for the current running thread. */ | ||
496 | current = cores[CURRENT_CORE].running; | ||
497 | |||
498 | /* At next task switch scheduler will immediately change the thread | ||
499 | * state (and we also force the task switch to happen). */ | ||
500 | if (timeout) | ||
501 | { | ||
502 | #ifdef THREAD_EXTRA_CHECKS | ||
503 | /* We can store only one thread to the "list" if thread is used | ||
504 | * in other list (such as core's list for sleeping tasks). */ | ||
505 | if (*list) | ||
506 | panicf("Blocking violation T->*B"); | ||
507 | #endif | ||
508 | |||
509 | current->statearg = | ||
510 | SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout); | ||
511 | *list = current; | ||
512 | |||
513 | /* Now force a task switch and block until we have been woken up | ||
514 | * by another thread or timeout is reached. */ | ||
515 | switch_thread(true, NULL); | ||
516 | |||
517 | /* If timeout is reached, we must set list back to NULL here. */ | ||
518 | *list = NULL; | ||
519 | } | ||
520 | else | ||
521 | { | ||
522 | #ifdef THREAD_EXTRA_CHECKS | ||
523 | /* We are not allowed to mix blocking types in one queue. */ | ||
524 | if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO) | ||
525 | panicf("Blocking violation B->*T"); | ||
526 | #endif | ||
527 | |||
528 | current->statearg = SET_STATE(STATE_BLOCKED, 0); | ||
529 | |||
530 | /* Now force a task switch and block until we have been woken up | ||
531 | * by another thread or timeout is reached. */ | ||
532 | switch_thread(true, list); | ||
533 | } | ||
534 | |||
535 | /* Clear all flags to indicate we are up and running again. */ | ||
536 | current->statearg = 0; | ||
290 | } | 537 | } |
291 | 538 | ||
539 | void wakeup_thread(struct thread_entry **list) | ||
540 | { | ||
541 | struct thread_entry *thread; | ||
542 | |||
543 | /* Check if there is a blocked thread at all. */ | ||
544 | if (*list == NULL) | ||
545 | return ; | ||
546 | |||
547 | /* Wake up the last thread first. */ | ||
548 | thread = *list; | ||
549 | |||
550 | /* Determine thread's current state. */ | ||
551 | switch (GET_STATE(thread->statearg)) | ||
552 | { | ||
553 | case STATE_BLOCKED: | ||
554 | /* Remove thread from the list of blocked threads and add it | ||
555 | * to the scheduler's list of running processes. */ | ||
556 | remove_from_list(list, thread); | ||
557 | add_to_list(&cores[CURRENT_CORE].running, thread); | ||
558 | thread->statearg = 0; | ||
559 | break; | ||
560 | |||
561 | case STATE_BLOCKED_W_TMO: | ||
562 | /* Just remove the timeout to cause scheduler to immediately | ||
563 | * wake up the thread. */ | ||
564 | thread->statearg &= 0xC0000000; | ||
565 | *list = NULL; | ||
566 | break; | ||
567 | |||
568 | default: | ||
569 | /* Nothing to do. Thread has already been woken up | ||
570 | * or it's state is not blocked or blocked with timeout. */ | ||
571 | return ; | ||
572 | } | ||
573 | } | ||
292 | 574 | ||
293 | /*--------------------------------------------------------------------------- | 575 | /*--------------------------------------------------------------------------- |
294 | * Create thread on the current core. | 576 | * Create thread on the current core. |
295 | * Return ID if context area could be allocated, else -1. | 577 | * Return ID if context area could be allocated, else -1. |
296 | *--------------------------------------------------------------------------- | 578 | *--------------------------------------------------------------------------- |
297 | */ | 579 | */ |
298 | int create_thread(void (*function)(void), void* stack, int stack_size, | 580 | struct thread_entry* |
299 | const char *name) | 581 | create_thread(void (*function)(void), void* stack, int stack_size, |
582 | const char *name IF_PRIO(, int priority)) | ||
300 | { | 583 | { |
301 | return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, | 584 | return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, |
302 | name); | 585 | name IF_PRIO(, priority)); |
303 | } | 586 | } |
304 | 587 | ||
305 | /*--------------------------------------------------------------------------- | 588 | /*--------------------------------------------------------------------------- |
@@ -307,18 +590,28 @@ int create_thread(void (*function)(void), void* stack, int stack_size, | |||
307 | * Return ID if context area could be allocated, else -1. | 590 | * Return ID if context area could be allocated, else -1. |
308 | *--------------------------------------------------------------------------- | 591 | *--------------------------------------------------------------------------- |
309 | */ | 592 | */ |
310 | int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, | 593 | struct thread_entry* |
311 | const char *name) | 594 | create_thread_on_core(unsigned int core, void (*function)(void), |
595 | void* stack, int stack_size, | ||
596 | const char *name IF_PRIO(, int priority)) | ||
312 | { | 597 | { |
313 | unsigned int i; | 598 | unsigned int i; |
314 | unsigned int stacklen; | 599 | unsigned int stacklen; |
315 | unsigned int *stackptr; | 600 | unsigned int *stackptr; |
601 | int n; | ||
316 | struct regs *regs; | 602 | struct regs *regs; |
317 | struct thread_entry *thread; | 603 | struct thread_entry *thread; |
318 | 604 | ||
319 | if (cores[core].num_threads >= MAXTHREADS) | 605 | for (n = 0; n < MAXTHREADS; n++) |
320 | return -1; | 606 | { |
321 | 607 | if (cores[core].threads[n].name == NULL) | |
608 | break; | ||
609 | } | ||
610 | |||
611 | if (n == MAXTHREADS) | ||
612 | return NULL; | ||
613 | |||
614 | |||
322 | /* Munge the stack to make it easy to spot stack overflows */ | 615 | /* Munge the stack to make it easy to spot stack overflows */ |
323 | stacklen = stack_size / sizeof(int); | 616 | stacklen = stack_size / sizeof(int); |
324 | stackptr = stack; | 617 | stackptr = stack; |
@@ -328,10 +621,17 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack | |||
328 | } | 621 | } |
329 | 622 | ||
330 | /* Store interesting information */ | 623 | /* Store interesting information */ |
331 | thread = &cores[core].threads[cores[core].num_threads]; | 624 | thread = &cores[core].threads[n]; |
332 | thread->name = name; | 625 | thread->name = name; |
333 | thread->stack = stack; | 626 | thread->stack = stack; |
334 | thread->stack_size = stack_size; | 627 | thread->stack_size = stack_size; |
628 | thread->statearg = 0; | ||
629 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
630 | thread->priority = priority; | ||
631 | highest_priority = 100; | ||
632 | #endif | ||
633 | add_to_list(&cores[core].running, thread); | ||
634 | |||
335 | regs = &thread->context; | 635 | regs = &thread->context; |
336 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) | 636 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) |
337 | /* Align stack to an even 32 bit boundary */ | 637 | /* Align stack to an even 32 bit boundary */ |
@@ -343,8 +643,7 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack | |||
343 | #endif | 643 | #endif |
344 | regs->start = (void*)function; | 644 | regs->start = (void*)function; |
345 | 645 | ||
346 | wake_up_thread(); | 646 | return thread; |
347 | return cores[core].num_threads++; /* return the current ID, e.g for remove_thread() */ | ||
348 | } | 647 | } |
349 | 648 | ||
350 | /*--------------------------------------------------------------------------- | 649 | /*--------------------------------------------------------------------------- |
@@ -352,44 +651,58 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack | |||
352 | * Parameter is the ID as returned from create_thread(). | 651 | * Parameter is the ID as returned from create_thread(). |
353 | *--------------------------------------------------------------------------- | 652 | *--------------------------------------------------------------------------- |
354 | */ | 653 | */ |
355 | void remove_thread(int threadnum) | 654 | void remove_thread(struct thread_entry *thread) |
356 | { | 655 | { |
357 | remove_thread_on_core(CURRENT_CORE, threadnum); | 656 | if (thread == NULL) |
657 | thread = cores[CURRENT_CORE].running; | ||
658 | |||
659 | /* Free the entry by removing thread name. */ | ||
660 | thread->name = NULL; | ||
661 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
662 | highest_priority = 100; | ||
663 | #endif | ||
664 | |||
665 | if (thread == cores[CURRENT_CORE].running) | ||
666 | { | ||
667 | remove_from_list(&cores[CURRENT_CORE].running, thread); | ||
668 | switch_thread(false, NULL); | ||
669 | return ; | ||
670 | } | ||
671 | |||
672 | if (thread == cores[CURRENT_CORE].sleeping) | ||
673 | remove_from_list(&cores[CURRENT_CORE].sleeping, thread); | ||
674 | |||
675 | remove_from_list(NULL, thread); | ||
358 | } | 676 | } |
359 | 677 | ||
360 | /*--------------------------------------------------------------------------- | 678 | #ifdef HAVE_PRIORITY_SCHEDULING |
361 | * Remove a thread on the specified core from the scheduler. | 679 | void thread_set_priority(struct thread_entry *thread, int priority) |
362 | * Parameters are the core and the ID as returned from create_thread(). | ||
363 | *--------------------------------------------------------------------------- | ||
364 | */ | ||
365 | void remove_thread_on_core(unsigned int core, int threadnum) | ||
366 | { | 680 | { |
367 | int i; | 681 | if (thread == NULL) |
368 | 682 | thread = cores[CURRENT_CORE].running; | |
369 | if (threadnum >= cores[core].num_threads) | 683 | |
370 | return; | 684 | thread->priority = priority; |
371 | 685 | highest_priority = 100; | |
372 | cores[core].num_threads--; | ||
373 | for (i=threadnum; i<cores[core].num_threads-1; i++) | ||
374 | { /* move all entries which are behind */ | ||
375 | cores[core].threads[i] = cores[core].threads[i+1]; | ||
376 | } | ||
377 | |||
378 | if (cores[core].current_thread == threadnum) /* deleting the current one? */ | ||
379 | cores[core].current_thread = cores[core].num_threads; /* set beyond last, avoid store harm */ | ||
380 | else if (cores[core].current_thread > threadnum) /* within the moved positions? */ | ||
381 | cores[core].current_thread--; /* adjust it, point to same context again */ | ||
382 | } | 686 | } |
687 | #endif | ||
383 | 688 | ||
384 | void init_threads(void) | 689 | void init_threads(void) |
385 | { | 690 | { |
386 | unsigned int core = CURRENT_CORE; | 691 | unsigned int core = CURRENT_CORE; |
387 | 692 | ||
388 | cores[core].num_threads = 1; /* We have 1 thread to begin with */ | 693 | memset(cores, 0, sizeof cores); |
389 | cores[core].current_thread = 0; /* The current thread is number 0 */ | 694 | cores[core].sleeping = NULL; |
695 | cores[core].running = NULL; | ||
390 | cores[core].threads[0].name = main_thread_name; | 696 | cores[core].threads[0].name = main_thread_name; |
391 | /* In multiple core setups, each core has a different stack. There is probably | 697 | cores[core].threads[0].statearg = 0; |
392 | a much better way to do this. */ | 698 | #ifdef HAVE_PRIORITY_SCHEDULING |
699 | cores[core].threads[0].priority = PRIORITY_USER_INTERFACE; | ||
700 | highest_priority = 100; | ||
701 | #endif | ||
702 | add_to_list(&cores[core].running, &cores[core].threads[0]); | ||
703 | |||
704 | /* In multiple core setups, each core has a different stack. There is probably | ||
705 | a much better way to do this. */ | ||
393 | if (core == CPU) | 706 | if (core == CPU) |
394 | { | 707 | { |
395 | cores[CPU].threads[0].stack = stackbegin; | 708 | cores[CPU].threads[0].stack = stackbegin; |
@@ -405,28 +718,24 @@ void init_threads(void) | |||
405 | #else | 718 | #else |
406 | cores[core].threads[0].context.start = 0; /* thread 0 already running */ | 719 | cores[core].threads[0].context.start = 0; /* thread 0 already running */ |
407 | #endif | 720 | #endif |
408 | cores[core].num_sleepers = 0; | ||
409 | } | ||
410 | |||
411 | int thread_stack_usage(int threadnum) | ||
412 | { | ||
413 | return thread_stack_usage_on_core(CURRENT_CORE, threadnum); | ||
414 | } | 721 | } |
415 | 722 | ||
416 | int thread_stack_usage_on_core(unsigned int core, int threadnum) | 723 | int thread_stack_usage(const struct thread_entry *thread) |
417 | { | 724 | { |
418 | unsigned int i; | 725 | unsigned int i; |
419 | unsigned int *stackptr = cores[core].threads[threadnum].stack; | 726 | unsigned int *stackptr = thread->stack; |
420 | |||
421 | if (threadnum >= cores[core].num_threads) | ||
422 | return -1; | ||
423 | 727 | ||
424 | for (i = 0;i < cores[core].threads[threadnum].stack_size/sizeof(int);i++) | 728 | for (i = 0;i < thread->stack_size/sizeof(int);i++) |
425 | { | 729 | { |
426 | if (stackptr[i] != DEADBEEF) | 730 | if (stackptr[i] != DEADBEEF) |
427 | break; | 731 | break; |
428 | } | 732 | } |
429 | 733 | ||
430 | return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) / | 734 | return ((thread->stack_size - i * sizeof(int)) * 100) / |
431 | cores[core].threads[threadnum].stack_size; | 735 | thread->stack_size; |
736 | } | ||
737 | |||
738 | int thread_get_status(const struct thread_entry *thread) | ||
739 | { | ||
740 | return GET_STATE(thread->statearg); | ||
432 | } | 741 | } |