Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 75 additions & 60 deletions src/scheduler_mp.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,27 @@
#include <rtthread.h>
#include <rthw.h>

#define DBG_TAG "kernel.scheduler"
#define DBG_LVL DBG_INFO
#define DBG_TAG "kernel.scheduler"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
static struct rt_spinlock _mp_scheduler_lock;

#define SCHEDULER_LOCK_FLAG(percpu) ((percpu)->sched_lock_flag)

#define SCHEDULER_ENTER_CRITICAL(curthr) \
do \
{ \
if (curthr) RT_SCHED_CTX(curthr).critical_lock_nest++; \
#define SCHEDULER_ENTER_CRITICAL(curthr) \
do \
{ \
if (curthr) \
RT_SCHED_CTX(curthr).critical_lock_nest++; \
} while (0)

#define SCHEDULER_EXIT_CRITICAL(curthr) \
do \
{ \
if (curthr) RT_SCHED_CTX(curthr).critical_lock_nest--; \
#define SCHEDULER_EXIT_CRITICAL(curthr) \
do \
{ \
if (curthr) \
RT_SCHED_CTX(curthr).critical_lock_nest--; \
} while (0)

#define SCHEDULER_CONTEXT_LOCK(percpu) \
Expand Down Expand Up @@ -202,7 +204,7 @@ rt_inline rt_base_t _get_global_highest_ready_prio(void)
return highest_ready_priority;
}

rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu* pcpu)
rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu *pcpu)
{
rt_ubase_t number;
rt_ubase_t local_highest_ready_priority;
Expand All @@ -226,7 +228,7 @@ rt_inline rt_base_t _get_global_highest_ready_prio(void)
return __rt_ffs(rt_thread_ready_priority_group) - 1;
}

rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu* pcpu)
rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu *pcpu)
{
return __rt_ffs(pcpu->priority_group) - 1;
}
Expand All @@ -236,11 +238,11 @@ rt_inline rt_base_t _get_local_highest_ready_prio(struct rt_cpu* pcpu)
/*
* get the highest priority thread in ready queue
*/
static struct rt_thread* _scheduler_get_highest_priority_thread(rt_ubase_t *highest_prio)
static struct rt_thread *_scheduler_get_highest_priority_thread(rt_ubase_t *highest_prio)
{
struct rt_thread *highest_priority_thread;
rt_ubase_t highest_ready_priority, local_highest_ready_priority;
struct rt_cpu* pcpu = rt_cpu_self();
struct rt_cpu *pcpu = rt_cpu_self();

highest_ready_priority = _get_global_highest_ready_prio();
local_highest_ready_priority = _get_local_highest_ready_prio(pcpu);
Expand Down Expand Up @@ -282,11 +284,13 @@ static void _sched_insert_thread_locked(struct rt_thread *thread)
int cpu_id;
int bind_cpu;
rt_uint32_t cpu_mask;
rt_uint8_t stat_before;
rt_bool_t insert_at_head;

if ((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
{
/* already in ready queue */
return ;
return;
}
else if (RT_SCHED_CTX(thread).oncpu != RT_CPU_DETACHED)
{
Expand All @@ -295,13 +299,26 @@ static void _sched_insert_thread_locked(struct rt_thread *thread)
* this is a RUNNING thread. So here we reset it's status and let it go.
*/
RT_SCHED_CTX(thread).stat = RT_THREAD_RUNNING | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK);
return ;
return;
}

/* READY thread, insert to ready queue */
RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK);
stat_before = RT_SCHED_CTX(thread).stat;
RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (stat_before & ~RT_THREAD_STAT_MASK);

/* A thread that was preempted while it still had time slices left keeps the
* head of the ready list, so that it is scheduled first next time.
*
* Every other case -- time slice consumed (@c RT_THREAD_STAT_YIELD set),
* resumed from an IPC pending list, or freshly started -- is appended to the
* tail. Inserting those at the head would reverse the order in which
* same-priority threads became ready, which breaks the FIFO fairness of the
* ready list (see RT-Thread issue #8459).
*/
insert_at_head = (((stat_before & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) &&
((stat_before & RT_THREAD_STAT_YIELD_MASK) == 0));

cpu_id = rt_hw_cpu_id();
cpu_id = rt_hw_cpu_id();
bind_cpu = RT_SCHED_CTX(thread).bind_cpu;

/* insert thread to ready list */
Expand All @@ -312,17 +329,15 @@ static void _sched_insert_thread_locked(struct rt_thread *thread)
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
rt_thread_ready_priority_group |= RT_SCHED_PRIV(thread).number_mask;

/* there is no time slices left(YIELD), inserting thread before ready list*/
if((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0)
if (insert_at_head)
{
rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
}
/* there are some time slices left, inserting thread after ready list to schedule it firstly at next time*/
else
{
rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
}

cpu_mask = RT_CPU_MASK ^ (1 << cpu_id);
Expand All @@ -337,17 +352,15 @@ static void _sched_insert_thread_locked(struct rt_thread *thread)
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
pcpu->priority_group |= RT_SCHED_PRIV(thread).number_mask;

/* there is no time slices left(YIELD), inserting thread before ready list*/
if((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0)
if (insert_at_head)
{
rt_list_insert_before(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
rt_list_insert_after(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
}
/* there are some time slices left, inserting thread after ready list to schedule it firstly at next time*/
else
{
rt_list_insert_after(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
rt_list_insert_before(&(rt_cpu_index(bind_cpu)->priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
}

if (cpu_id != bind_cpu)
Expand Down Expand Up @@ -435,15 +448,15 @@ void rt_system_scheduler_init(void)

rt_spin_lock_init(&_mp_scheduler_lock);

for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset++)
{
rt_list_init(&rt_thread_priority_table[offset]);
}

for (cpu = 0; cpu < RT_CPUS_NR; cpu++)
{
struct rt_cpu *pcpu = rt_cpu_index(cpu);
for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
struct rt_cpu *pcpu = rt_cpu_index(cpu);
for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset++)
{
rt_list_init(&pcpu->priority_table[offset]);
}
Expand Down Expand Up @@ -566,7 +579,9 @@ rt_err_t rt_sched_lock(rt_sched_lock_level_t *plvl)
{
rt_base_t level;
if (!plvl)
{
return -RT_EINVAL;
}

SCHEDULER_LOCK(level);
*plvl = level;
Expand Down Expand Up @@ -642,8 +657,7 @@ static rt_thread_t _prepare_context_switch_locked(int cpu_id,
if ((RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
{
/* check if current thread can be running on current core again */
if (RT_SCHED_CTX(current_thread).bind_cpu == RT_CPUS_NR
|| RT_SCHED_CTX(current_thread).bind_cpu == cpu_id)
if (RT_SCHED_CTX(current_thread).bind_cpu == RT_CPUS_NR || RT_SCHED_CTX(current_thread).bind_cpu == cpu_id)
{
/* if current_thread is the highest runnable thread */
if (RT_SCHED_PRIV(current_thread).current_priority < highest_ready_priority)
Expand Down Expand Up @@ -777,12 +791,12 @@ static void _sched_thread_process_signal(struct rt_thread *current_thread)
/* lock is released above */
}

#define SCHED_THREAD_PREPROCESS_SIGNAL(pcpu, curthr) \
do \
{ \
SCHEDULER_CONTEXT_LOCK(pcpu); \
_sched_thread_preprocess_signal(curthr); \
SCHEDULER_CONTEXT_UNLOCK(pcpu); \
#define SCHED_THREAD_PREPROCESS_SIGNAL(pcpu, curthr) \
do \
{ \
SCHEDULER_CONTEXT_LOCK(pcpu); \
_sched_thread_preprocess_signal(curthr); \
SCHEDULER_CONTEXT_UNLOCK(pcpu); \
} while (0)
#define SCHED_THREAD_PREPROCESS_SIGNAL_LOCKED(curthr) \
_sched_thread_preprocess_signal(curthr)
Expand Down Expand Up @@ -822,12 +836,12 @@ rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t level)
{
struct rt_thread *to_thread;
struct rt_thread *current_thread;
struct rt_cpu *pcpu;
int cpu_id;
rt_err_t error = RT_EOK;
struct rt_cpu *pcpu;
int cpu_id;
rt_err_t error = RT_EOK;

cpu_id = rt_hw_cpu_id();
pcpu = rt_cpu_index(cpu_id);
pcpu = rt_cpu_index(cpu_id);
current_thread = pcpu->current_thread;

if (!current_thread)
Expand Down Expand Up @@ -923,23 +937,23 @@ void rt_schedule(void)
rt_base_t level;
struct rt_thread *to_thread;
struct rt_thread *current_thread;
struct rt_cpu *pcpu;
int cpu_id;
struct rt_cpu *pcpu;
int cpu_id;

/* enter ciritical region of percpu scheduling context */
level = rt_hw_local_irq_disable();

/* get percpu scheduling context */
cpu_id = rt_hw_cpu_id();
pcpu = rt_cpu_index(cpu_id);
pcpu = rt_cpu_index(cpu_id);
current_thread = pcpu->current_thread;

/* whether do switch in interrupt */
if (rt_atomic_load(&(pcpu->irq_nest)))
{
pcpu->irq_switch_flag = 1;
rt_hw_local_irq_enable(level);
return ; /* -RT_ESCHEDISR */
return; /* -RT_ESCHEDISR */
}

/* forbid any recursive entries of schedule() */
Expand Down Expand Up @@ -1015,16 +1029,16 @@ void rt_schedule(void)
*/
void rt_scheduler_do_irq_switch(void *context)
{
int cpu_id;
rt_base_t level;
struct rt_cpu *pcpu;
int cpu_id;
rt_base_t level;
struct rt_cpu *pcpu;
struct rt_thread *to_thread;
struct rt_thread *current_thread;

level = rt_hw_local_irq_disable();

cpu_id = rt_hw_cpu_id();
pcpu = rt_cpu_index(cpu_id);
pcpu = rt_cpu_index(cpu_id);
current_thread = pcpu->current_thread;

/* forbid any recursive entries of schedule() */
Expand Down Expand Up @@ -1147,7 +1161,7 @@ void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_ui

/* priority init */
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
RT_SCHED_PRIV(thread).init_priority = priority;
RT_SCHED_PRIV(thread).init_priority = priority;
RT_SCHED_PRIV(thread).current_priority = priority;

/* don't add to scheduler queue as init thread */
Expand All @@ -1166,7 +1180,6 @@ void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_ui
/* lock init */
RT_SCHED_CTX(thread).critical_lock_nest = 0;
#endif /* RT_USING_SMP */

}

/**
Expand Down Expand Up @@ -1220,7 +1233,7 @@ void rt_sched_thread_startup(struct rt_thread *thread)
*/
void rt_sched_post_ctx_switch(struct rt_thread *thread)
{
struct rt_cpu* pcpu = rt_cpu_self();
struct rt_cpu *pcpu = rt_cpu_self();
rt_thread_t from_thread = pcpu->current_thread;

RT_ASSERT(rt_hw_interrupt_is_disabled());
Expand Down Expand Up @@ -1269,13 +1282,13 @@ void rt_exit_critical_safe(rt_base_t critical_level)
int dummy = 1;
_critical_error_occurred = 1;

rt_kprintf("%s: un-compatible critical level\n" \
rt_kprintf("%s: un-compatible critical level\n"
"\tCurrent %d\n\tCaller %d\n",
__func__, RT_SCHED_CTX(current_thread).critical_lock_nest,
critical_level);
rt_backtrace();

while (dummy) ;
while (dummy);
}
}
rt_exit_critical();
Expand Down Expand Up @@ -1427,7 +1440,9 @@ void rt_exit_critical(void)
FREE_THREAD_SELF(level);

if (need_resched)
{
rt_schedule();
}
}
else
{
Expand Down
Loading
Loading