os_sched.c
2026/7/19大约 9 分钟附录源码附录
os_sched.c
路径: kernel\source\os_sched.c
/**
***********************************************************************************************************************
* Copyright (c) 2020, China Mobile Communications Group Co.,Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @file os_sched.c
*
* @brief This file implements the sched functions.
*
* @revision
* Date Author Notes
* 2020-10-13 OneOS Team First Version
***********************************************************************************************************************
*/
#include <oneos_config.h>
#include <os_types.h>
#include <os_stddef.h>
#include <os_assert.h>
#include <os_errno.h>
#include <os_task.h>
#include <arch_interrupt.h>
#include <string.h>
#include <arch_misc.h>
#include "os_kernel_internal.h"
struct readyq_bitmap
{
#if OS_TASK_PRIORITY_MAX > 32
#if OS_TASK_PRIORITY_MAX > 256
#error "OS_TASK_PRIORITY_MAX can not be greater than 256 !!!"
#endif
/* Maximum priority level, 256 */
uint32_t priority_group_bmap; /* Lookup table for priority_bmap */
uint8_t priority_bmap[(OS_TASK_PRIORITY_MAX + 7) / 8]; /* Lookup table for priority_list_array */
#else
uint32_t priority_bmap; /* Lookup table for priority_list_array */
#endif
os_list_node_t priority_list_array[OS_TASK_PRIORITY_MAX]; /* Doubly linked list head */
};
#ifdef OS_USING_SMP
os_task_t *g_os_current_task[OS_SMP_MAX_CPUS] = {OS_NULL};
os_task_t *g_os_next_task[OS_SMP_MAX_CPUS] = {OS_NULL};
#if OS_SMP_MAX_CPUS >= 32
#error "OS_SMP_MAX_CPUS can not be greater than 31 !!!"
#endif
static uint32_t g_os_need_sched_bit = 0;
static uint32_t g_os_same_prio_sched_bit = 0;
extern int32_t g_os_int_nest_cnt[];
static int16_t gs_os_sched_lock_cnt[OS_SMP_MAX_CPUS] = {0};
/*
* Define the global lock scheduler variable. If this is non-zero, scheduler is
* locked. It is used to prevent task schedule.
*/
static struct readyq_bitmap gs_os_global_readyq;
static struct readyq_bitmap gs_os_aff_readyq[OS_SMP_MAX_CPUS] = {0};
#else
os_task_t *g_os_current_task = OS_NULL;
os_task_t *g_os_next_task = OS_NULL;
os_task_t *g_os_high_task = OS_NULL; /*highest priority task */
/*
* Define the global lock scheduler variable. If this is non-zero, scheduler is
* locked. It is used to prevent task schedule.
*/
int16_t g_os_sched_lock_cnt = 0;
static struct readyq_bitmap gs_os_readyq; /*Global priority ready queue*/
#endif
OS_INLINE void _k_readq_bmap_init(struct readyq_bitmap *readyq)
{
uint32_t i;
#if OS_TASK_PRIORITY_MAX > 32
readyq->priority_group_bmap = 0;
memset(&readyq->priority_bmap[0], 0, sizeof(readyq->priority_bmap));
#else
readyq->priority_bmap = 0; /* lookup table for priority_list_array */
#endif
for (i = 0; i < OS_TASK_PRIORITY_MAX; i++)
{
os_list_init(&readyq->priority_list_array[i]);
}
return;
}
OS_INLINE void _k_readq_bmap_set(struct readyq_bitmap *readyq, uint8_t current_priority)
{
#if OS_TASK_PRIORITY_MAX > 32
readyq->priority_group_bmap |= (1 << ((uint32_t)current_priority >> 3));
readyq->priority_bmap[current_priority >> 3] |= (1 << (current_priority & 0x7));
#else
readyq->priority_bmap |= 1U << current_priority;
#endif
return;
}
OS_INLINE void _k_readq_bmap_clear(struct readyq_bitmap *readyq, uint8_t current_priority)
{
#if OS_TASK_PRIORITY_MAX > 32
readyq->priority_bmap[current_priority >> 3] &= ~(1 << (current_priority & 0x7));
if (readyq->priority_bmap[current_priority >> 3] == 0)
{
readyq->priority_group_bmap &= ~(1 << ((uint32_t)current_priority >> 3));
}
#else
readyq->priority_bmap &= ~(1U << current_priority);
#endif
return;
}
OS_INLINE struct os_task *_k_readyq_bmap_highest_task(struct readyq_bitmap *readyq)
{
struct os_task *highest_task;
uint8_t highest_priority;
#if OS_TASK_PRIORITY_MAX > 32
os_ubase_t priority_offset;
#endif
highest_task = OS_NULL;
#if OS_TASK_PRIORITY_MAX > 32
if (readyq->priority_group_bmap != 0)
{
priority_offset = os_ffs(readyq->priority_group_bmap) - 1;
highest_priority = (priority_offset << 3) + os_ffs(readyq->priority_bmap[priority_offset]) - 1;
highest_task = os_list_entry(readyq->priority_list_array[highest_priority].next, os_task_t, task_node);
}
#else
if (readyq->priority_bmap != 0)
{
highest_priority = os_ffs(readyq->priority_bmap) - 1;
highest_task = os_list_entry(readyq->priority_list_array[highest_priority].next, os_task_t, task_node);
}
#endif
return highest_task;
}
#ifdef OS_USING_SMP
OS_INLINE void _k_readyq_bmap_put_head(struct readyq_bitmap *readyq, struct os_task *task, uint8_t priority)
{
_k_readq_bmap_set(readyq, priority);
os_list_add(&readyq->priority_list_array[priority], &task->task_node);
return;
}
OS_INLINE void _k_readyq_bmap_put(struct readyq_bitmap *readyq, struct os_task *task, uint8_t priority)
{
_k_readq_bmap_set(readyq, priority);
os_list_add_tail(&readyq->priority_list_array[priority], &task->task_node);
return;
}
OS_INLINE void _k_readyq_bmap_remove(struct readyq_bitmap *readyq, struct os_task *task, uint8_t priority)
{
const os_list_node_t *task_list_head;
task_list_head = &readyq->priority_list_array[priority];
os_list_del(&task->task_node);
if (task_list_head == task_list_head->next)
{
/*clear mapbit*/
_k_readq_bmap_clear(readyq, priority);
}
return;
}
/**
***********************************************************************************************************************
* @brief This function just puts the task on the ready queue.
*
* @details When the running task is to be scheduled out, if the current task is READY state
* (because the running task is not on the ready queue), you need to put the task in the ready queue.
* When the "current" task is preempted by a high-priority task, the time slice of the current task is
* not used up, so add the "current" task to the readq header.
*
* @param[in] task Task control block.
*
* @return None.
***********************************************************************************************************************
*/
static void k_sched_readyq_put_head(struct os_task *task)
{
uint8_t priority;
int32_t cpu_affinity;
#ifdef OS_USING_KERNEL_LOCK_CHECK
OS_ASSERT((1 == k_kernel_lock_owne()));
#endif
/* If a task is will to be destroyed and it may be "deinited" status
OS_ASSERT((OS_KOBJ_INITED == task->object_inited)); */
cpu_affinity = task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)),
"Task: %s Affinity %d Invalid\r\n",
task->name,
cpu_affinity);
priority = task->current_priority;
if (cpu_affinity == -1)
{
_k_readyq_bmap_put_head(&gs_os_global_readyq, task, priority);
}
else
{
_k_readyq_bmap_put_head(&gs_os_aff_readyq[cpu_affinity], task, priority);
}
}
/**
***********************************************************************************************************************
* @brief This function just puts the task on the ready queue.
*
* @details When the running task is to be scheduled out, if the current task is READY state
* (because the running task is not on the ready queue), you need to put the task in the ready queue.
* When the "current" task takes the initiative to give up the CPU, add the "current" task to the
* end of readq.
*
* @param[in] task Task control block.
*
* @return None.
***********************************************************************************************************************
*/
static void k_sched_readyq_put_tail(struct os_task *task)
{
uint8_t priority;
int32_t cpu_affinity;
#ifdef OS_USING_KERNEL_LOCK_CHECK
OS_ASSERT((1 == k_kernel_lock_owne()));
#endif
/* If a task is will to be destroyed and it may be "deinited" status
OS_ASSERT((OS_KOBJ_INITED == task->object_inited)); */
cpu_affinity = task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)),
"Task: %s Affinity %d Invalid\r\n",
task->name,
cpu_affinity);
priority = task->current_priority;
if (cpu_affinity == -1)
{
_k_readyq_bmap_put(&gs_os_global_readyq, task, priority);
}
else
{
_k_readyq_bmap_put(&gs_os_aff_readyq[cpu_affinity], task, priority);
}
}
static os_task_t *_k_highest_task(int32_t current_cpu_index)
{
struct os_task *highest_task;
struct os_task *aff_highest_task;
struct os_task *global_highest_task;
aff_highest_task = _k_readyq_bmap_highest_task(&gs_os_aff_readyq[current_cpu_index]);
global_highest_task = _k_readyq_bmap_highest_task(&gs_os_global_readyq);
if ((aff_highest_task != OS_NULL) && (global_highest_task != OS_NULL))
{
if (aff_highest_task->current_priority <= global_highest_task->current_priority)
{
highest_task = aff_highest_task;
}
else
{
highest_task = global_highest_task;
}
}
else if (aff_highest_task != OS_NULL)
{
highest_task = aff_highest_task;
}
else if (global_highest_task != OS_NULL)
{
highest_task = global_highest_task;
}
else
{
/* When a cpu-x scheduling is triggered, due to the delay of cpu-x's response to scheduling,
after other cpu-y fetches this task, cpu-x cannot find the task. */
highest_task = OS_NULL;
}
return highest_task;
}
/* set cpu ipis by compare candidate_task priority with all other cpu's current task priority
if candidate_task priority is higher than other, should set cpu ipi,
when first cpu ipi already set, then skip it, find second cpu ini to be set */
static void k_preferred_cpu_found(int32_t current_cpu_index, const struct os_task *candidate_task)
{
int32_t cpu_affinity;
int32_t cpu_index;
int32_t cpu_score;
int32_t best_score;
int32_t best_cpu_index;
const struct os_task *cpu_current_task;
cpu_affinity = candidate_task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)),
"Task: %s Affinity %d Invalid\r\n",
candidate_task->name,
cpu_affinity);
if (cpu_affinity == -1)
{
best_cpu_index = -1;
best_score = -1;
for (cpu_index = 0; cpu_index < OS_SMP_MAX_CPUS; cpu_index++)
{
cpu_current_task = g_os_current_task[cpu_index];
/*The CPU has not started scheduling */
if ((OS_NULL == cpu_current_task) || OS_BIT_GET(g_os_need_sched_bit, cpu_index) ||
(gs_os_sched_lock_cnt[cpu_index] != 0) ||
(candidate_task->current_priority >= cpu_current_task->current_priority))
{
continue;
}
cpu_score = cpu_current_task->current_priority << 8; /*OS_TASK_PRIORITY_MAX < 256*/
if (cpu_index == current_cpu_index)
{
cpu_score++;
}
if (cpu_score > best_score)
{
best_score = cpu_score;
best_cpu_index = cpu_index;
}
}
if (-1 != best_cpu_index)
{
OS_BIT_SET(g_os_need_sched_bit, best_cpu_index);
}
}
else
{
/*Task binding CPU*/
cpu_current_task = g_os_current_task[cpu_affinity];
if (OS_NULL != cpu_current_task)
{
if ((candidate_task->current_priority < cpu_current_task->current_priority) &&
(gs_os_sched_lock_cnt[cpu_affinity] == 0))
{
OS_BIT_SET(g_os_need_sched_bit, cpu_affinity);
if (cpu_current_task->cpu_affinity == -1)
{
if ((cpu_current_task->state & OS_TASK_STATE_READY) != 0)
{
k_preferred_cpu_found(current_cpu_index, cpu_current_task);
}
}
}
}
}
}
// set cpu ipis by compare candidate_task priority with all other cpu's current task priority
// if candidate_task priority is higher than other, should set cpu ipi
static void k_preferred_cpu_all(int32_t current_cpu_index, const struct os_task *candidate_task)
{
int32_t cpu_affinity;
uint32_t cpu_index;
const struct os_task *cpu_current_task;
cpu_affinity = candidate_task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)),
"Task: %s Affinity %d Invalid\r\n",
candidate_task->name,
cpu_affinity);
if (cpu_affinity == -1)
{
for (cpu_index = 0; cpu_index < OS_SMP_MAX_CPUS; cpu_index++)
{
cpu_current_task = g_os_current_task[cpu_index];
/*The CPU has not started scheduling */
if ((OS_NULL == cpu_current_task) || (gs_os_sched_lock_cnt[cpu_index] != 0) ||
(candidate_task->current_priority >= cpu_current_task->current_priority))
{
continue;
}
OS_BIT_SET(g_os_need_sched_bit, cpu_index);
}
}
else
{
/*Task binding CPU*/
cpu_current_task = g_os_current_task[cpu_affinity];
if (OS_NULL != cpu_current_task)
{
if ((candidate_task->current_priority < cpu_current_task->current_priority) &&
(gs_os_sched_lock_cnt[cpu_affinity] == 0))
{
OS_BIT_SET(g_os_need_sched_bit, cpu_affinity);
if (cpu_current_task->cpu_affinity == -1)
{
if ((cpu_current_task->state & OS_TASK_STATE_READY) != 0)
{
k_preferred_cpu_all(current_cpu_index, cpu_current_task);
}
}
}
}
}
}
#endif
/**
***********************************************************************************************************************
* @brief This function put a task on the ready queue.
*
* @details The highest priority task is calculated when the priority ready queue is inserted.
*
* @param[in] task Task control block.
*
* @return None.
***********************************************************************************************************************
*/
void k_readyq_put(struct os_task *task)
{
#ifdef OS_USING_SMP
uint8_t priority;
int32_t current_cpu_index;
int32_t candidate_cpu_index;
int32_t cpu_affinity;
#ifdef OS_USING_KERNEL_LOCK_CHECK
OS_ASSERT((1 == k_kernel_lock_owne()));
#endif
OS_ASSERT((OS_KOBJ_INITED == task->object_inited));
current_cpu_index = os_cpu_id_get();
cpu_affinity = task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)),
"Task: %s Affinity %d Invalid\r\n",
task->name,
cpu_affinity);
if (task->cpu_index != -1)
{
/* The running task is puted the ready queue during task switching.
When modifying the priority of the "current" task,
you need to remove the task from readq first,
and then add it to the readq of the corresponding priority.*/
OS_BIT_SET(g_os_need_sched_bit, task->cpu_index);
}
else
{
priority = task->current_priority;
if (cpu_affinity == -1)
{
_k_readyq_bmap_put(&gs_os_global_readyq, task, priority);
}
else
{
_k_readyq_bmap_put(&gs_os_aff_readyq[cpu_affinity], task, priority);
}
#if defined OS_SCHED_STRATEGY_SKIP_IPI_SET
k_preferred_cpu_found(current_cpu_index, task);
#elif defined(OS_SCHED_STRATEGY_ALL_IPI_SET)
k_preferred_cpu_all(current_cpu_index, task);
#else
#endif
}
#else
uint8_t priority;
priority = task->current_priority;
if ((g_os_high_task == OS_NULL) || (priority < g_os_high_task->current_priority))
{
g_os_high_task = task;
}
_k_readq_bmap_set(&gs_os_readyq, priority);
os_list_add_tail(&gs_os_readyq.priority_list_array[priority], &task->task_node);
return;
#endif
}
#ifdef OS_USING_SMP
/**
***********************************************************************************************************************
* @brief This function remove a task from the ready queue.
*
* @details When a task is scheduled to run, the task needs to be removed from the ready queue,so that it
* is convenient to find the highest priority task that is not running and is READY state.
*
* @param[in] task Task control block.
*
* @return None.
***********************************************************************************************************************
*/
static void k_sched_readyq_remove(struct os_task *task)
{
uint8_t priority;
int32_t cpu_affinity;
#ifdef OS_USING_KERNEL_LOCK_CHECK
OS_ASSERT((1 == k_kernel_lock_owne()));
#endif
/* If a task is will to be destroyed and it may be "deinited" status
OS_ASSERT((OS_KOBJ_INITED == task->object_inited)); */
cpu_affinity = task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)),
"Task: %s Affinity %d Invalid\r\n",
task->name,
cpu_affinity);
priority = task->current_priority;
if (cpu_affinity == -1)
{
_k_readyq_bmap_remove(&gs_os_global_readyq, task, priority);
}
else
{
_k_readyq_bmap_remove(&gs_os_aff_readyq[cpu_affinity], task, priority);
}
}
#endif
/**
***********************************************************************************************************************
* @brief This function remove a task from the ready queue.
*
* @details The highest priority task is calculated when remove a task from the ready queue.
*
* @param[in] task Task control block.
*
* @return None.
***********************************************************************************************************************
*/
/* clang-format off */
void k_readyq_remove(struct os_task *task)
{
#ifdef OS_USING_SMP
uint8_t priority;
int32_t cpu_affinity;
#ifdef OS_USING_KERNEL_LOCK_CHECK
OS_ASSERT(1 == k_kernel_lock_owne());
#endif
cpu_affinity = task->cpu_affinity;
OS_ASSERT_EX(((cpu_affinity < OS_SMP_MAX_CPUS) && (cpu_affinity >= -1)), "Task: %s Affinity %d Invalid\r\n", task->name, cpu_affinity);
priority = task->current_priority;
if (task->cpu_index != -1)
{
/* The running task is removed from the ready queue during task switching. */
OS_BIT_SET(g_os_need_sched_bit, task->cpu_index);
}
else
{
if (cpu_affinity == -1)
{
_k_readyq_bmap_remove(&gs_os_global_readyq, task, priority);
}
else
{
_k_readyq_bmap_remove(&gs_os_aff_readyq[cpu_affinity], task, priority);
}
}
#else
os_list_node_t *task_list_head;
uint8_t priority;
uint8_t highest_priority;
priority = task->current_priority;
task_list_head = &gs_os_readyq.priority_list_array[priority];
os_list_del(&task->task_node);
if (os_list_empty(task_list_head))
{
/*clear mapbit*/
_k_readq_bmap_clear(&gs_os_readyq, priority);
if (task == g_os_high_task)
{
g_os_high_task = _k_readyq_bmap_highest_task(&gs_os_readyq);
}
}
else
{
if (task == g_os_high_task)
{
highest_priority = task->current_priority;
g_os_high_task = os_list_entry(gs_os_readyq.priority_list_array[highest_priority].next, os_task_t, task_node);
}
}
#endif
return;
}
/* clang-format on */
/**
***********************************************************************************************************************
* @brief This function move a task to the end of the ready queue.
*
* @details The highest priority task is recalculated.
*
* @param[in] task Task control block.
*
* @return None.
***********************************************************************************************************************
*/
os_bool_t k_readyq_move_tail(struct os_task *task)
{
#ifdef OS_USING_SMP
if ((gs_os_global_readyq.priority_list_array[task->current_priority].next !=
&gs_os_global_readyq.priority_list_array[task->current_priority]) ||
(gs_os_aff_readyq[task->cpu_index].priority_list_array[task->current_priority].next !=
&gs_os_aff_readyq[task->cpu_index].priority_list_array[task->current_priority]))
{
OS_BIT_SET(g_os_need_sched_bit, task->cpu_index);
OS_BIT_SET(g_os_same_prio_sched_bit, task->cpu_index);
return OS_TRUE;
}
else
{
return OS_FALSE;
}
#else
os_list_node_t *task_list_head;
uint8_t priority;
if (task->task_node.next == task->task_node.prev)
{
return OS_FALSE;
}
else
{
priority = task->current_priority;
task_list_head = &gs_os_readyq.priority_list_array[priority];
os_list_move_tail(task_list_head, &task->task_node);
if (task == g_os_high_task)
{
g_os_high_task = os_list_entry(gs_os_readyq.priority_list_array[priority].next, os_task_t, task_node);
}
return OS_TRUE;
}
#endif
}
/**
***********************************************************************************************************************
* @brief This function initialize kernel scheduling .
*
* @param[in] None.
*
* @return None.
***********************************************************************************************************************
*/
void k_sched_init(void)
{
#ifdef OS_USING_SMP
uint8_t i;
_k_readq_bmap_init(&gs_os_global_readyq);
for (i = 0; i < OS_SMP_MAX_CPUS; i++)
{
_k_readq_bmap_init(&gs_os_aff_readyq[i]);
}
#else
_k_readq_bmap_init(&gs_os_readyq);
#endif
return;
}
/**
***********************************************************************************************************************
* @brief This function start kernel scheduling .
*
* @details Run the first task (highest priority)
*
* @param[in] None.
*
* @return None.
***********************************************************************************************************************
*/
void k_start(void)
{
#ifdef OS_USING_SMP
OS_KERNEL_INIT();
int32_t current_cpu_index;
current_cpu_index = os_cpu_id_get();
OS_KERNEL_ENTER();
g_os_next_task[current_cpu_index] = _k_highest_task(current_cpu_index);
g_os_next_task[current_cpu_index]->cpu_index = current_cpu_index;
k_sched_readyq_remove(g_os_next_task[current_cpu_index]);
#else
g_os_next_task = g_os_high_task;
#endif
os_first_task_start();
/* Never come back. */
return;
}
#ifdef OS_USING_SMP
void secondary_cpu_start(void *arg)
{
k_start();
}
/**
***********************************************************************************************************************
* @brief This function exits the kernel critical section and triggers the schedule .
*
* @param[in] None.
*
* @return None.
***********************************************************************************************************************
*/
void k_kernel_exit_sched(os_ubase_t irq_save)
{
register int32_t current_cpu_index;
register int32_t need_sched;
current_cpu_index = os_cpu_id_get();
/*
* 1. Kernel is not initialized, must call k_start()
* 2. Schedule is locked
* 3. Interrupts are nested
*/
if ((OS_NULL == g_os_current_task[current_cpu_index]) || (0 != gs_os_sched_lock_cnt[current_cpu_index]) ||
(g_os_int_nest_cnt[current_cpu_index] > 0) || (0 == OS_BIT_GET(g_os_need_sched_bit, current_cpu_index)))
{
k_sched_send_ipi(current_cpu_index, g_os_need_sched_bit);
k_kernel_exit(irq_save);
}
else
{
if ((g_os_current_task[current_cpu_index]->state & OS_TASK_STATE_CLOSE) != 0)
{
_k_task_close(g_os_current_task[current_cpu_index]);
}
OS_BIT_CLR(g_os_need_sched_bit, current_cpu_index);
g_os_next_task[current_cpu_index] = _k_highest_task(current_cpu_index);
if (g_os_next_task[current_cpu_index] != OS_NULL)
{
if ((g_os_current_task[current_cpu_index]->state & OS_TASK_STATE_READY) != 0)
{
if (g_os_next_task[current_cpu_index]->current_priority <
g_os_current_task[current_cpu_index]->current_priority)
{
k_sched_readyq_put_head(g_os_current_task[current_cpu_index]);
#if defined(OS_SCHED_STRATEGY_SKIP_IPI_SET) && defined(OS_SCHED_SECONDARY_FOUND)
k_preferred_cpu_found(current_cpu_index, g_os_current_task[current_cpu_index]);
#endif
need_sched = 1;
}
else if ((g_os_next_task[current_cpu_index]->current_priority ==
g_os_current_task[current_cpu_index]->current_priority) &&
(OS_BIT_GET(g_os_same_prio_sched_bit, current_cpu_index) != 0))
{
OS_BIT_CLR(g_os_same_prio_sched_bit, current_cpu_index);
k_sched_readyq_put_tail(g_os_current_task[current_cpu_index]);
#if defined(OS_SCHED_STRATEGY_SKIP_IPI_SET) && defined(OS_SCHED_SECONDARY_FOUND)
k_preferred_cpu_found(current_cpu_index, g_os_current_task[current_cpu_index]);
#endif
need_sched = 1;
}
else
{
need_sched = 0;
}
}
else
{
need_sched = 1;
}
}
else
{
need_sched = 0;
}
if (1 == need_sched)
{
g_os_current_task[current_cpu_index]->cpu_index = -1;
g_os_next_task[current_cpu_index]->cpu_index = current_cpu_index;
k_sched_readyq_remove(g_os_next_task[current_cpu_index]);
k_sched_send_ipi(current_cpu_index, g_os_need_sched_bit);
os_task_switch();
os_irq_unlock(irq_save);
}
else
{
k_sched_send_ipi(current_cpu_index, g_os_need_sched_bit);
k_kernel_exit(irq_save);
}
}
return;
}
#endif
/**
***********************************************************************************************************************
* @brief This function lock task scheduling.
*
* @param[in] None.
*
* @return None.
***********************************************************************************************************************
*/
void os_schedule_lock(void)
{
OS_KERNEL_INIT();
OS_KERNEL_ENTER();
#ifdef OS_USING_SMP
gs_os_sched_lock_cnt[os_cpu_id_get()]++;
#else
g_os_sched_lock_cnt++;
#endif
OS_KERNEL_EXIT();
return;
}
/**
***********************************************************************************************************************
* @brief This function unlock task scheduling.
*
* @param[in] None.
*
* @return None.
***********************************************************************************************************************
*/
void os_schedule_unlock(void)
{
int16_t sched_lock_cnt;
#ifdef OS_USING_SMP
int32_t current_cpu_index;
#endif
OS_KERNEL_INIT();
OS_KERNEL_ENTER();
#ifdef OS_USING_SMP
current_cpu_index = os_cpu_id_get();
sched_lock_cnt = --gs_os_sched_lock_cnt[current_cpu_index];
#else
sched_lock_cnt = --g_os_sched_lock_cnt;
#endif
if (sched_lock_cnt == 0)
{
#ifdef OS_USING_SMP
OS_BIT_SET(g_os_need_sched_bit, current_cpu_index);
#endif
OS_KERNEL_EXIT_SCHED();
}
else if (sched_lock_cnt > 0)
{
OS_KERNEL_EXIT();
}
else
{
OS_ASSERT_EX(OS_FALSE, "Task use schedule lock correctly");
}
return;
}
/**
***********************************************************************************************************************
* @brief This function unlock task scheduling.
*
* @param[in] None.
*
* @return None.
***********************************************************************************************************************
*/
os_bool_t os_is_schedule_locked(void)
{
os_bool_t is_lock;
int16_t sched_lock_cnt;
OS_KERNEL_INIT();
is_lock = OS_FALSE;
OS_KERNEL_ENTER();
#ifdef OS_USING_SMP
sched_lock_cnt = gs_os_sched_lock_cnt[os_cpu_id_get()];
#else
sched_lock_cnt = g_os_sched_lock_cnt;
#endif
if (sched_lock_cnt > 0)
{
is_lock = OS_TRUE;
}
else if (sched_lock_cnt == 0)
{
;
}
else
{
#ifdef OS_USING_SMP
OS_ASSERT_EX(sched_lock_cnt >= 0,
"Task(%s) use schedule lock incorrectly.",
g_os_current_task[os_cpu_id_get()]->name);
#else
OS_ASSERT_EX(sched_lock_cnt >= 0, "Task(%s) use schedule lock incorrectly.", g_os_current_task->name);
#endif
}
OS_KERNEL_EXIT();
return is_lock;
}
#ifdef OS_USING_SMP
/* TODO: Interrupt nesting is not supported. */
void k_exit_int(void *context)
{
int32_t current_cpu_index;
int32_t need_sched;
current_cpu_index = os_cpu_id_get();
/*
* 1. Kernel is not initialized, must call k_start()
* 2. Schedule is locked
* 3. Call k_exit_int must disable interrupt
*/
if ((OS_NULL == g_os_current_task[current_cpu_index]) || (0 != gs_os_sched_lock_cnt[current_cpu_index]))
{
k_sched_send_ipi(current_cpu_index, g_os_need_sched_bit);
}
else
{
k_kernel_spin_lock();
need_sched = 0;
if ((OS_BIT_GET(g_os_need_sched_bit, current_cpu_index)) != 0)
{
if ((g_os_current_task[current_cpu_index]->state & OS_TASK_STATE_CLOSE) != 0)
{
_k_task_close(g_os_current_task[current_cpu_index]);
}
OS_BIT_CLR(g_os_need_sched_bit, current_cpu_index);
g_os_next_task[current_cpu_index] = _k_highest_task(current_cpu_index);
if (g_os_next_task[current_cpu_index] != OS_NULL)
{
if ((g_os_current_task[current_cpu_index]->state & OS_TASK_STATE_READY) != 0)
{
if (g_os_next_task[current_cpu_index]->current_priority <
g_os_current_task[current_cpu_index]->current_priority)
{
/* When the interrupt exits,
there may be no remaining use of the "current" task time slice
and it is preempted by high-priority tasks. */
if (0 == OS_BIT_GET(g_os_same_prio_sched_bit, current_cpu_index))
{
k_sched_readyq_put_head(g_os_current_task[current_cpu_index]);
}
else
{
OS_BIT_CLR(g_os_same_prio_sched_bit, current_cpu_index);
k_sched_readyq_put_tail(g_os_current_task[current_cpu_index]);
}
#if defined OS_SCHED_STRATEGY_SKIP_IPI_SET
k_preferred_cpu_found(current_cpu_index, g_os_current_task[current_cpu_index]);
#endif
need_sched = 1;
}
else if ((g_os_next_task[current_cpu_index]->current_priority ==
g_os_current_task[current_cpu_index]->current_priority) &&
(OS_BIT_GET(g_os_same_prio_sched_bit, current_cpu_index) != 0))
{
OS_BIT_CLR(g_os_same_prio_sched_bit, current_cpu_index);
k_sched_readyq_put_tail(g_os_current_task[current_cpu_index]);
#if defined OS_SCHED_STRATEGY_SKIP_IPI_SET
k_preferred_cpu_found(current_cpu_index, g_os_current_task[current_cpu_index]);
#endif
need_sched = 1;
}
else
{
need_sched = 0;
}
}
else
{
need_sched = 1;
}
}
}
if (1 == need_sched)
{
g_os_current_task[current_cpu_index]->cpu_index = -1;
g_os_next_task[current_cpu_index]->cpu_index = current_cpu_index;
k_sched_readyq_remove(g_os_next_task[current_cpu_index]);
k_sched_send_ipi(current_cpu_index, g_os_need_sched_bit);
os_int_task_switch(context);
}
else
{
k_sched_send_ipi(current_cpu_index, g_os_need_sched_bit);
k_kernel_spin_unlock();
}
}
}
#endif
#ifdef OS_USING_SMP
void k_sched_send_ipi(int32_t cpu, uint32_t need_sched_bits)
{
int32_t sched_cpu_index;
OS_BIT_CLR(need_sched_bits, cpu);
while (need_sched_bits != 0)
{
sched_cpu_index = os_ffs(need_sched_bits) - 1;
OS_BIT_CLR(need_sched_bits, sched_cpu_index);
os_hw_ipi_send(OS_SMP_IPI_SCHED, 1 << sched_cpu_index);
}
}
#endif