* @brief Pick the highest runnable thread, and pass the control to it * * @note caller should hold the scheduler context lock. lock will be released * before return from this routine */
| 623 | * before return from this routine |
| 624 | */ |
| 625 | static rt_thread_t _prepare_context_switch_locked(int cpu_id, |
| 626 | struct rt_cpu *pcpu, |
| 627 | rt_thread_t current_thread) |
| 628 | { |
| 629 | rt_thread_t to_thread = RT_NULL; |
| 630 | rt_ubase_t highest_ready_priority; |
| 631 | |
| 632 | /* quickly check if any other ready threads queuing */ |
| 633 | if (rt_thread_ready_priority_group != 0 || pcpu->priority_group != 0) |
| 634 | { |
| 635 | /* pick the highest ready thread */ |
| 636 | to_thread = _scheduler_get_highest_priority_thread(&highest_ready_priority); |
| 637 | |
| 638 | /* detach current thread from percpu scheduling context */ |
| 639 | RT_SCHED_CTX(current_thread).oncpu = RT_CPU_DETACHED; |
| 640 | |
| 641 | /* check if current thread should be put to ready queue, or scheduling again */ |
| 642 | if ((RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) |
| 643 | { |
| 644 | /* check if current thread can be running on current core again */ |
| 645 | if (RT_SCHED_CTX(current_thread).bind_cpu == RT_CPUS_NR |
| 646 | || RT_SCHED_CTX(current_thread).bind_cpu == cpu_id) |
| 647 | { |
| 648 | /* if current_thread is the highest runnable thread */ |
| 649 | if (RT_SCHED_PRIV(current_thread).current_priority < highest_ready_priority) |
| 650 | { |
| 651 | to_thread = current_thread; |
| 652 | } |
| 653 | /* or no higher-priority thread existed and it has remaining ticks */ |
| 654 | else if (RT_SCHED_PRIV(current_thread).current_priority == highest_ready_priority && |
| 655 | (RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_YIELD_MASK) == 0) |
| 656 | { |
| 657 | to_thread = current_thread; |
| 658 | } |
| 659 | /* otherwise give out the core */ |
| 660 | else |
| 661 | { |
| 662 | _sched_insert_thread_locked(current_thread); |
| 663 | } |
| 664 | } |
| 665 | else |
| 666 | { |
| 667 | /* put current_thread to ready queue of another core */ |
| 668 | _sched_insert_thread_locked(current_thread); |
| 669 | } |
| 670 | |
| 671 | /* consume the yield flags after scheduling */ |
| 672 | RT_SCHED_CTX(current_thread).stat &= ~RT_THREAD_STAT_YIELD_MASK; |
| 673 | } |
| 674 | |
| 675 | /** |
| 676 | * Now destination thread is determined, core is passed to it. Though |
| 677 | * the percpu scheduling context is not updated here, since the cpu |
| 678 | * is locked contiguously before all the scheduling works are done, it's |
| 679 | * safe to observe that current thread as the running thread on this |
| 680 | * core for any observers if they properly do the synchronization |
| 681 | * (take the SCHEDULER_LOCK). |
| 682 | */ |
no test coverage detected