1170 lines
36 KiB
C
1170 lines
36 KiB
C
/*
|
|
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "los_sched_pri.h"
|
|
#include "los_hw_pri.h"
|
|
#include "los_task_pri.h"
|
|
#include "los_process_pri.h"
|
|
#include "los_arch_mmu.h"
|
|
#ifdef LOSCFG_KERNEL_CPUP
|
|
#include "los_cpup_pri.h"
|
|
#endif
|
|
#include "los_hw_tick_pri.h"
|
|
#include "los_tick_pri.h"
|
|
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
|
|
#include "los_stackinfo_pri.h"
|
|
#endif
|
|
#include "los_mp.h"
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
#include "los_stat_pri.h"
|
|
#endif
|
|
|
|
#define OS_32BIT_MAX 0xFFFFFFFFUL
|
|
#define OS_SCHED_FIFO_TIMEOUT 0x7FFFFFFF
|
|
#define OS_PRIORITY_QUEUE_NUM 32
|
|
#define PRIQUEUE_PRIOR0_BIT 0x80000000U
|
|
#define OS_SCHED_TIME_SLICES_MIN ((5000 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 5ms */
|
|
#define OS_SCHED_TIME_SLICES_MAX ((LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE)
|
|
#define OS_SCHED_TIME_SLICES_DIFF (OS_SCHED_TIME_SLICES_MAX - OS_SCHED_TIME_SLICES_MIN)
|
|
#define OS_SCHED_READY_MAX 30
|
|
#define OS_TIME_SLICE_MIN (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 50us */
|
|
|
|
typedef struct {
|
|
LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM];
|
|
UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM];
|
|
UINT32 queueBitmap;
|
|
} SchedQueue;
|
|
|
|
typedef struct {
|
|
SchedQueue queueList[OS_PRIORITY_QUEUE_NUM];
|
|
UINT32 queueBitmap;
|
|
SchedScan taskScan;
|
|
SchedScan swtmrScan;
|
|
} Sched;
|
|
|
|
STATIC Sched *g_sched = NULL;
|
|
STATIC UINT64 g_schedTickMaxResponseTime;
|
|
UINT64 g_sysSchedStartTime = OS_64BIT_MAX;
|
|
|
|
#ifdef LOSCFG_SCHED_TICK_DEBUG
|
|
#define OS_SCHED_DEBUG_DATA_NUM 1000
|
|
typedef struct {
|
|
UINT32 tickResporeTime[OS_SCHED_DEBUG_DATA_NUM];
|
|
UINT32 index;
|
|
UINT32 setTickCount;
|
|
UINT64 oldResporeTime;
|
|
} SchedTickDebug;
|
|
STATIC SchedTickDebug *g_schedTickDebug = NULL;
|
|
|
|
STATIC UINT32 OsSchedDebugInit(VOID)
|
|
{
|
|
UINT32 size = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
|
|
g_schedTickDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem0, size);
|
|
if (g_schedTickDebug == NULL) {
|
|
return LOS_ERRNO_TSK_NO_MEMORY;
|
|
}
|
|
|
|
(VOID)memset_s(g_schedTickDebug, size, 0, size);
|
|
return LOS_OK;
|
|
}
|
|
|
|
VOID OsSchedDebugRecordData(VOID)
|
|
{
|
|
SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
|
|
if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
|
|
UINT64 currTime = OsGetCurrSchedTimeCycle();
|
|
schedDebug->tickResporeTime[schedDebug->index] = currTime - schedDebug->oldResporeTime;
|
|
schedDebug->oldResporeTime = currTime;
|
|
schedDebug->index++;
|
|
}
|
|
}
|
|
|
|
SchedTickDebug *OsSchedDebugGet(VOID)
|
|
{
|
|
return g_schedTickDebug;
|
|
}
|
|
|
|
UINT32 OsShellShowTickRespo(VOID)
|
|
{
|
|
UINT32 intSave;
|
|
UINT16 cpu;
|
|
UINT64 allTime;
|
|
|
|
UINT32 tickSize = sizeof(SchedTickDebug) * LOSCFG_KERNEL_CORE_NUM;
|
|
SchedTickDebug *schedDebug = (SchedTickDebug *)LOS_MemAlloc(m_aucSysMem1, tickSize);
|
|
if (schedDebug == NULL) {
|
|
return LOS_NOK;
|
|
}
|
|
|
|
UINT32 sortLinkNum[LOSCFG_KERNEL_CORE_NUM];
|
|
SCHEDULER_LOCK(intSave);
|
|
(VOID)memcpy_s((CHAR *)schedDebug, tickSize, (CHAR *)OsSchedDebugGet(), tickSize);
|
|
(VOID)memset_s((CHAR *)OsSchedDebugGet(), tickSize, 0, tickSize);
|
|
for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
|
|
sortLinkNum[cpu] = OsPercpuGetByID(cpu)->taskSortLink.nodeNum + OsPercpuGetByID(cpu)->swtmrSortLink.nodeNum;
|
|
}
|
|
SCHEDULER_UNLOCK(intSave);
|
|
|
|
for (cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
|
|
SchedTickDebug *schedData = &schedDebug[cpu];
|
|
PRINTK("cpu : %u sched data num : %u set time count : %u SortMax : %u\n",
|
|
cpu, schedData->index, schedData->setTickCount, sortLinkNum[cpu]);
|
|
UINT32 *data = schedData->tickResporeTime;
|
|
allTime = 0;
|
|
for (UINT32 i = 1; i < schedData->index; i++) {
|
|
allTime += data[i];
|
|
UINT32 timeUs = (data[i] * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
|
|
PRINTK(" %u(%u)", timeUs, timeUs / OS_US_PER_TICK);
|
|
if ((i != 0) && ((i % 5) == 0)) { /* A row of 5 data */
|
|
PRINTK("\n");
|
|
}
|
|
}
|
|
|
|
allTime = (allTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
|
|
PRINTK("\nTick Indicates the average response period: %llu(us)\n", allTime / (schedData->index - 1));
|
|
}
|
|
|
|
(VOID)LOS_MemFree(m_aucSysMem1, schedDebug);
|
|
return LOS_OK;
|
|
}
|
|
|
|
#else
|
|
|
|
UINT32 OsShellShowTickRespo(VOID)
|
|
{
|
|
return LOS_NOK;
|
|
}
|
|
#endif
|
|
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
UINT32 OsShellShowSchedParam(VOID)
|
|
{
|
|
UINT64 averRunTime;
|
|
UINT64 averTimeSlice;
|
|
UINT64 averSchedWait;
|
|
UINT64 averPendTime;
|
|
UINT32 intSave;
|
|
UINT32 size = g_taskMaxNum * sizeof(LosTaskCB);
|
|
LosTaskCB *taskCBArray = LOS_MemAlloc(m_aucSysMem1, size);
|
|
if (taskCBArray == NULL) {
|
|
return LOS_NOK;
|
|
}
|
|
|
|
SCHEDULER_LOCK(intSave);
|
|
(VOID)memcpy_s(taskCBArray, size, g_taskCBArray, size);
|
|
SCHEDULER_UNLOCK(intSave);
|
|
PRINTK(" Tid AverRunTime(us) SwitchCount AverTimeSlice(us) TimeSliceCount AverReadyWait(us) "
|
|
"AverPendTime(us) TaskName \n");
|
|
for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
|
|
LosTaskCB *taskCB = taskCBArray + tid;
|
|
if (OsTaskIsUnused(taskCB)) {
|
|
continue;
|
|
}
|
|
|
|
averRunTime = 0;
|
|
averTimeSlice = 0;
|
|
averPendTime = 0;
|
|
averSchedWait = 0;
|
|
|
|
if (taskCB->schedStat.switchCount >= 1) {
|
|
averRunTime = taskCB->schedStat.runTime / taskCB->schedStat.switchCount;
|
|
averRunTime = (averRunTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
|
|
}
|
|
|
|
if (taskCB->schedStat.timeSliceCount > 1) {
|
|
averTimeSlice = taskCB->schedStat.timeSliceTime / (taskCB->schedStat.timeSliceCount - 1);
|
|
averTimeSlice = (averTimeSlice * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
|
|
}
|
|
|
|
if (taskCB->schedStat.pendCount > 1) {
|
|
averPendTime = taskCB->schedStat.pendTime / taskCB->schedStat.pendCount;
|
|
averPendTime = (averPendTime * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
|
|
}
|
|
|
|
if (taskCB->schedStat.waitSchedCount > 0) {
|
|
averSchedWait = taskCB->schedStat.waitSchedTime / taskCB->schedStat.waitSchedCount;
|
|
averSchedWait = (averSchedWait * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US;
|
|
}
|
|
|
|
PRINTK("%5u%19llu%15llu%19llu%18llu%19llu%18llu %-32s\n", taskCB->taskID,
|
|
averRunTime, taskCB->schedStat.switchCount,
|
|
averTimeSlice, taskCB->schedStat.timeSliceCount - 1,
|
|
averSchedWait, averPendTime, taskCB->taskName);
|
|
}
|
|
|
|
(VOID)LOS_MemFree(m_aucSysMem1, taskCBArray);
|
|
|
|
return LOS_OK;
|
|
}
|
|
|
|
#else
|
|
|
|
UINT32 OsShellShowSchedParam(VOID)
|
|
{
|
|
return LOS_NOK;
|
|
}
|
|
#endif
|
|
|
|
UINT32 OsSchedSetTickTimerType(UINT32 timerType)
|
|
{
|
|
switch (timerType) {
|
|
case 32: /* 32 bit timer */
|
|
g_schedTickMaxResponseTime = OS_32BIT_MAX;
|
|
break;
|
|
case 64: /* 64 bit timer */
|
|
g_schedTickMaxResponseTime = OS_64BIT_MAX;
|
|
break;
|
|
default:
|
|
PRINT_ERR("Unsupported Tick Timer type, The system only supports 32 and 64 bit tick timers\n");
|
|
return LOS_NOK;
|
|
}
|
|
|
|
return LOS_OK;
|
|
}
|
|
|
|
STATIC VOID OsSchedSetStartTime(UINT64 currCycle)
|
|
{
|
|
if (g_sysSchedStartTime == OS_64BIT_MAX) {
|
|
g_sysSchedStartTime = currCycle;
|
|
}
|
|
}
|
|
|
|
STATIC INLINE VOID OsTimeSliceUpdate(LosTaskCB *taskCB, UINT64 currTime)
|
|
{
|
|
LOS_ASSERT(currTime >= taskCB->startTime);
|
|
|
|
INT32 incTime = (currTime - taskCB->startTime - taskCB->irqUsedTime);
|
|
|
|
LOS_ASSERT(incTime >= 0);
|
|
|
|
if (taskCB->policy == LOS_SCHED_RR) {
|
|
taskCB->timeSlice -= incTime;
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
taskCB->schedStat.timeSliceRealTime += incTime;
|
|
#endif
|
|
}
|
|
taskCB->irqUsedTime = 0;
|
|
taskCB->startTime = currTime;
|
|
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
taskCB->schedStat.allRuntime += incTime;
|
|
#endif
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedTickReload(Percpu *currCpu, UINT64 nextResponseTime, UINT32 responseID, BOOL isTimeSlice)
|
|
{
|
|
UINT64 currTime, nextExpireTime;
|
|
UINT32 usedTime;
|
|
|
|
currTime = OsGetCurrSchedTimeCycle();
|
|
if (currCpu->tickStartTime != 0) {
|
|
usedTime = currTime - currCpu->tickStartTime;
|
|
currCpu->tickStartTime = 0;
|
|
} else {
|
|
usedTime = 0;
|
|
}
|
|
|
|
if ((nextResponseTime > usedTime) && ((nextResponseTime - usedTime) > OS_TICK_RESPONSE_PRECISION)) {
|
|
nextResponseTime -= usedTime;
|
|
} else {
|
|
nextResponseTime = OS_TICK_RESPONSE_PRECISION;
|
|
}
|
|
|
|
nextExpireTime = currTime + nextResponseTime;
|
|
if (nextExpireTime >= currCpu->responseTime) {
|
|
return;
|
|
}
|
|
|
|
if (isTimeSlice) {
|
|
/* The expiration time of the current system is the thread's slice expiration time */
|
|
currCpu->responseID = responseID;
|
|
} else {
|
|
currCpu->responseID = OS_INVALID_VALUE;
|
|
}
|
|
currCpu->responseTime = nextExpireTime;
|
|
HalClockTickTimerReload(nextResponseTime);
|
|
|
|
#ifdef LOSCFG_SCHED_TICK_DEBUG
|
|
SchedTickDebug *schedDebug = &g_schedTickDebug[ArchCurrCpuid()];
|
|
if (schedDebug->index < OS_SCHED_DEBUG_DATA_NUM) {
|
|
schedDebug->setTickCount++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedSetNextExpireTime(UINT64 startTime, UINT32 responseID,
|
|
UINT64 taskEndTime, UINT32 oldResponseID)
|
|
{
|
|
UINT64 nextExpireTime = OsGetNextExpireTime(startTime);
|
|
Percpu *currCpu = OsPercpuGet();
|
|
UINT64 nextResponseTime;
|
|
BOOL isTimeSlice = FALSE;
|
|
|
|
currCpu->schedFlag &= ~INT_PEND_TICK;
|
|
if (currCpu->responseID == oldResponseID) {
|
|
/* This time has expired, and the next time the theory has expired is infinite */
|
|
currCpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
|
|
}
|
|
|
|
/* The current thread's time slice has been consumed, but the current system lock task cannot
|
|
* trigger the schedule to release the CPU
|
|
*/
|
|
if ((nextExpireTime > taskEndTime) && ((nextExpireTime - taskEndTime) > OS_SCHED_MINI_PERIOD)) {
|
|
nextExpireTime = taskEndTime;
|
|
isTimeSlice = TRUE;
|
|
}
|
|
|
|
if ((currCpu->responseTime > nextExpireTime) &&
|
|
((currCpu->responseTime - nextExpireTime) >= OS_TICK_RESPONSE_PRECISION)) {
|
|
nextResponseTime = nextExpireTime - startTime;
|
|
if (nextResponseTime > g_schedTickMaxResponseTime) {
|
|
nextResponseTime = g_schedTickMaxResponseTime;
|
|
}
|
|
} else {
|
|
/* There is no point earlier than the current expiration date */
|
|
currCpu->tickStartTime = 0;
|
|
return;
|
|
}
|
|
|
|
OsSchedTickReload(currCpu, nextResponseTime, responseID, isTimeSlice);
|
|
}
|
|
|
|
VOID OsSchedUpdateExpireTime(UINT64 startTime)
|
|
{
|
|
UINT64 endTime;
|
|
Percpu *cpu = OsPercpuGet();
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
|
|
if (!OS_SCHEDULER_ACTIVE || OS_INT_ACTIVE) {
|
|
cpu->schedFlag |= INT_PEND_TICK;
|
|
return;
|
|
}
|
|
|
|
if (runTask->policy == LOS_SCHED_RR) {
|
|
LOS_SpinLock(&g_taskSpin);
|
|
INT32 timeSlice = (runTask->timeSlice <= OS_TIME_SLICE_MIN) ? runTask->initTimeSlice : runTask->timeSlice;
|
|
LOS_SpinUnlock(&g_taskSpin);
|
|
endTime = startTime + timeSlice;
|
|
} else {
|
|
endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
|
|
}
|
|
|
|
OsSchedSetNextExpireTime(startTime, runTask->taskID, endTime, runTask->taskID);
|
|
}
|
|
|
|
STATIC INLINE UINT32 OsSchedCalculateTimeSlice(UINT16 proPriority, UINT16 priority)
|
|
{
|
|
UINT32 ratTime, readTasks;
|
|
|
|
SchedQueue *queueList = &g_sched->queueList[proPriority];
|
|
readTasks = queueList->readyTasks[priority];
|
|
if (readTasks > OS_SCHED_READY_MAX) {
|
|
return OS_SCHED_TIME_SLICES_MIN;
|
|
}
|
|
ratTime = ((OS_SCHED_READY_MAX - readTasks) * OS_SCHED_TIME_SLICES_DIFF) / OS_SCHED_READY_MAX;
|
|
return (ratTime + OS_SCHED_TIME_SLICES_MIN);
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedPriQueueEnHead(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
|
|
{
|
|
SchedQueue *queueList = &g_sched->queueList[proPriority];
|
|
LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
|
|
UINT32 *bitMap = &queueList->queueBitmap;
|
|
|
|
/*
|
|
* Task control blocks are inited as zero. And when task is deleted,
|
|
* and at the same time would be deleted from priority queue or
|
|
* other lists, task pend node will restored as zero.
|
|
*/
|
|
LOS_ASSERT(priqueueItem->pstNext == NULL);
|
|
|
|
if (*bitMap == 0) {
|
|
g_sched->queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority;
|
|
}
|
|
|
|
if (LOS_ListEmpty(&priQueueList[priority])) {
|
|
*bitMap |= PRIQUEUE_PRIOR0_BIT >> priority;
|
|
}
|
|
|
|
LOS_ListHeadInsert(&priQueueList[priority], priqueueItem);
|
|
queueList->readyTasks[priority]++;
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedPriQueueEnTail(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
|
|
{
|
|
SchedQueue *queueList = &g_sched->queueList[proPriority];
|
|
LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
|
|
UINT32 *bitMap = &queueList->queueBitmap;
|
|
|
|
/*
|
|
* Task control blocks are inited as zero. And when task is deleted,
|
|
* and at the same time would be deleted from priority queue or
|
|
* other lists, task pend node will restored as zero.
|
|
*/
|
|
LOS_ASSERT(priqueueItem->pstNext == NULL);
|
|
|
|
if (*bitMap == 0) {
|
|
g_sched->queueBitmap |= PRIQUEUE_PRIOR0_BIT >> proPriority;
|
|
}
|
|
|
|
if (LOS_ListEmpty(&priQueueList[priority])) {
|
|
*bitMap |= PRIQUEUE_PRIOR0_BIT >> priority;
|
|
}
|
|
|
|
LOS_ListTailInsert(&priQueueList[priority], priqueueItem);
|
|
queueList->readyTasks[priority]++;
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedPriQueueDelete(UINT32 proPriority, LOS_DL_LIST *priqueueItem, UINT32 priority)
|
|
{
|
|
SchedQueue *queueList = &g_sched->queueList[proPriority];
|
|
LOS_DL_LIST *priQueueList = &queueList->priQueueList[0];
|
|
UINT32 *bitMap = &queueList->queueBitmap;
|
|
|
|
LOS_ListDelete(priqueueItem);
|
|
queueList->readyTasks[priority]--;
|
|
if (LOS_ListEmpty(&priQueueList[priority])) {
|
|
*bitMap &= ~(PRIQUEUE_PRIOR0_BIT >> priority);
|
|
}
|
|
|
|
if (*bitMap == 0) {
|
|
g_sched->queueBitmap &= ~(PRIQUEUE_PRIOR0_BIT >> proPriority);
|
|
}
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedWakePendTimeTask(UINT64 currTime, LosTaskCB *taskCB, BOOL *needSchedule)
|
|
{
|
|
#ifndef LOSCFG_SCHED_DEBUG
|
|
(VOID)currTime;
|
|
#endif
|
|
|
|
LOS_SpinLock(&g_taskSpin);
|
|
UINT16 tempStatus = taskCB->taskStatus;
|
|
if (tempStatus & (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_DELAY)) {
|
|
taskCB->taskStatus &= ~(OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY);
|
|
if (tempStatus & OS_TASK_STATUS_PENDING) {
|
|
#ifdef LOSCFG_KERNEL_LITEIPC
|
|
taskCB->ipcStatus &= ~IPC_THREAD_STATUS_PEND;
|
|
#endif
|
|
taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT;
|
|
LOS_ListDelete(&taskCB->pendList);
|
|
taskCB->taskMux = NULL;
|
|
OsTaskWakeClearPendMask(taskCB);
|
|
}
|
|
|
|
if (!(tempStatus & OS_TASK_STATUS_SUSPENDED)) {
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
taskCB->schedStat.pendTime += currTime - taskCB->startTime;
|
|
taskCB->schedStat.pendCount++;
|
|
#endif
|
|
OsSchedTaskEnQueue(taskCB);
|
|
*needSchedule = TRUE;
|
|
}
|
|
}
|
|
|
|
LOS_SpinUnlock(&g_taskSpin);
|
|
}
|
|
|
|
STATIC INLINE BOOL OsSchedScanTimerList(VOID)
|
|
{
|
|
Percpu *cpu = OsPercpuGet();
|
|
BOOL needSchedule = FALSE;
|
|
SortLinkAttribute *taskSortLink = &OsPercpuGet()->taskSortLink;
|
|
LOS_DL_LIST *listObject = &taskSortLink->sortLink;
|
|
/*
|
|
* When task is pended with timeout, the task block is on the timeout sortlink
|
|
* (per cpu) and ipc(mutex,sem and etc.)'s block at the same time, it can be waken
|
|
* up by either timeout or corresponding ipc it's waiting.
|
|
*
|
|
* Now synchronize sortlink preocedure is used, therefore the whole task scan needs
|
|
* to be protected, preventing another core from doing sortlink deletion at same time.
|
|
*/
|
|
LOS_SpinLock(&cpu->taskSortLinkSpin);
|
|
|
|
if (LOS_ListEmpty(listObject)) {
|
|
LOS_SpinUnlock(&cpu->taskSortLinkSpin);
|
|
return needSchedule;
|
|
}
|
|
|
|
SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
|
|
UINT64 currTime = OsGetCurrSchedTimeCycle();
|
|
while (sortList->responseTime <= currTime) {
|
|
LosTaskCB *taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);
|
|
OsDeleteNodeSortLink(taskSortLink, &taskCB->sortList);
|
|
LOS_SpinUnlock(&cpu->taskSortLinkSpin);
|
|
|
|
OsSchedWakePendTimeTask(currTime, taskCB, &needSchedule);
|
|
|
|
LOS_SpinLock(&cpu->taskSortLinkSpin);
|
|
if (LOS_ListEmpty(listObject)) {
|
|
break;
|
|
}
|
|
|
|
sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
|
|
}
|
|
|
|
LOS_SpinUnlock(&cpu->taskSortLinkSpin);
|
|
|
|
return needSchedule;
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedEnTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB)
|
|
{
|
|
LOS_ASSERT(!(taskCB->taskStatus & OS_TASK_STATUS_READY));
|
|
|
|
switch (taskCB->policy) {
|
|
case LOS_SCHED_RR: {
|
|
if (taskCB->timeSlice > OS_TIME_SLICE_MIN) {
|
|
OsSchedPriQueueEnHead(processCB->priority, &taskCB->pendList, taskCB->priority);
|
|
} else {
|
|
taskCB->initTimeSlice = OsSchedCalculateTimeSlice(processCB->priority, taskCB->priority);
|
|
taskCB->timeSlice = taskCB->initTimeSlice;
|
|
OsSchedPriQueueEnTail(processCB->priority, &taskCB->pendList, taskCB->priority);
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
taskCB->schedStat.timeSliceTime = taskCB->schedStat.timeSliceRealTime;
|
|
taskCB->schedStat.timeSliceCount++;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
case LOS_SCHED_FIFO: {
|
|
/* The time slice of FIFO is always greater than 0 unless the yield is called */
|
|
if ((taskCB->timeSlice > OS_TIME_SLICE_MIN) && (taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
|
|
OsSchedPriQueueEnHead(processCB->priority, &taskCB->pendList, taskCB->priority);
|
|
} else {
|
|
taskCB->initTimeSlice = OS_SCHED_FIFO_TIMEOUT;
|
|
taskCB->timeSlice = taskCB->initTimeSlice;
|
|
OsSchedPriQueueEnTail(processCB->priority, &taskCB->pendList, taskCB->priority);
|
|
}
|
|
break;
|
|
}
|
|
case LOS_SCHED_IDLE:
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
taskCB->schedStat.timeSliceCount = 1;
|
|
#endif
|
|
break;
|
|
default:
|
|
LOS_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
taskCB->taskStatus &= ~OS_TASK_STATUS_BLOCKED;
|
|
taskCB->taskStatus |= OS_TASK_STATUS_READY;
|
|
|
|
processCB->processStatus &= ~(OS_PROCESS_STATUS_INIT | OS_PROCESS_STATUS_PENDING);
|
|
processCB->processStatus |= OS_PROCESS_STATUS_READY;
|
|
processCB->readyTaskNum++;
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedDeTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB)
|
|
{
|
|
if (taskCB->policy != LOS_SCHED_IDLE) {
|
|
OsSchedPriQueueDelete(processCB->priority, &taskCB->pendList, taskCB->priority);
|
|
}
|
|
taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
|
|
|
|
processCB->readyTaskNum--;
|
|
if (processCB->readyTaskNum == 0) {
|
|
processCB->processStatus &= ~OS_PROCESS_STATUS_READY;
|
|
}
|
|
}
|
|
|
|
VOID OsSchedTaskDeQueue(LosTaskCB *taskCB)
|
|
{
|
|
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);
|
|
|
|
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
|
|
OsSchedDeTaskQueue(taskCB, processCB);
|
|
}
|
|
|
|
if (processCB->processStatus & OS_PROCESS_STATUS_READY) {
|
|
return;
|
|
}
|
|
|
|
/* If the current process has only the current thread running,
|
|
* the process becomes blocked after the thread leaves the scheduling queue
|
|
*/
|
|
if (OS_PROCESS_GET_RUNTASK_COUNT(processCB->processStatus) == 1) {
|
|
processCB->processStatus |= OS_PROCESS_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
VOID OsSchedTaskEnQueue(LosTaskCB *taskCB)
|
|
{
|
|
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
|
|
taskCB->startTime = OsGetCurrSchedTimeCycle();
|
|
}
|
|
#endif
|
|
OsSchedEnTaskQueue(taskCB, processCB);
|
|
}
|
|
|
|
VOID OsSchedTaskExit(LosTaskCB *taskCB)
|
|
{
|
|
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);
|
|
|
|
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
|
|
OsSchedTaskDeQueue(taskCB);
|
|
processCB->processStatus &= ~OS_PROCESS_STATUS_PENDING;
|
|
} else if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) {
|
|
LOS_ListDelete(&taskCB->pendList);
|
|
taskCB->taskStatus &= ~OS_TASK_STATUS_PENDING;
|
|
}
|
|
|
|
if (taskCB->taskStatus & (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)) {
|
|
OsDeleteSortLink(&taskCB->sortList, OS_SORT_LINK_TASK);
|
|
taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME);
|
|
}
|
|
}
|
|
|
|
VOID OsSchedYield(VOID)
|
|
{
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
|
|
runTask->timeSlice = 0;
|
|
|
|
runTask->startTime = OsGetCurrSchedTimeCycle();
|
|
OsSchedTaskEnQueue(runTask);
|
|
OsSchedResched();
|
|
}
|
|
|
|
VOID OsSchedDelay(LosTaskCB *runTask, UINT32 tick)
|
|
{
|
|
OsSchedTaskDeQueue(runTask);
|
|
runTask->taskStatus |= OS_TASK_STATUS_DELAY;
|
|
runTask->waitTimes = tick;
|
|
|
|
OsSchedResched();
|
|
}
|
|
|
|
UINT32 OsSchedTaskWait(LOS_DL_LIST *list, UINT32 ticks, BOOL needSched)
|
|
{
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
OsSchedTaskDeQueue(runTask);
|
|
|
|
runTask->taskStatus |= OS_TASK_STATUS_PENDING;
|
|
LOS_ListTailInsert(list, &runTask->pendList);
|
|
|
|
if (ticks != LOS_WAIT_FOREVER) {
|
|
runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME;
|
|
runTask->waitTimes = ticks;
|
|
}
|
|
|
|
if (needSched == TRUE) {
|
|
OsSchedResched();
|
|
if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
|
|
runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
|
|
return LOS_ERRNO_TSK_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
return LOS_OK;
|
|
}
|
|
|
|
VOID OsSchedTaskWake(LosTaskCB *resumedTask)
|
|
{
|
|
LOS_ListDelete(&resumedTask->pendList);
|
|
resumedTask->taskStatus &= ~OS_TASK_STATUS_PENDING;
|
|
|
|
if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) {
|
|
OsDeleteSortLink(&resumedTask->sortList, OS_SORT_LINK_TASK);
|
|
resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
|
|
}
|
|
|
|
if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) {
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->startTime;
|
|
resumedTask->schedStat.pendCount++;
|
|
#endif
|
|
OsSchedTaskEnQueue(resumedTask);
|
|
}
|
|
}
|
|
|
|
BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 policy, UINT16 priority)
|
|
{
|
|
if (taskCB->policy != policy) {
|
|
taskCB->policy = policy;
|
|
taskCB->timeSlice = 0;
|
|
}
|
|
|
|
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
|
|
OsSchedTaskDeQueue(taskCB);
|
|
taskCB->priority = priority;
|
|
OsSchedTaskEnQueue(taskCB);
|
|
return TRUE;
|
|
}
|
|
|
|
taskCB->priority = priority;
|
|
if (taskCB->taskStatus & OS_TASK_STATUS_INIT) {
|
|
OsSchedTaskEnQueue(taskCB);
|
|
return TRUE;
|
|
}
|
|
|
|
if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL OsSchedModifyProcessSchedParam(LosProcessCB *processCB, UINT16 policy, UINT16 priority)
|
|
{
|
|
LosTaskCB *taskCB = NULL;
|
|
BOOL needSched = FALSE;
|
|
(VOID)policy;
|
|
|
|
if (processCB->processStatus & OS_PROCESS_STATUS_READY) {
|
|
LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &processCB->threadSiblingList, LosTaskCB, threadList) {
|
|
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
|
|
OsSchedPriQueueDelete(processCB->priority, &taskCB->pendList, taskCB->priority);
|
|
OsSchedPriQueueEnTail(priority, &taskCB->pendList, taskCB->priority);
|
|
needSched = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
processCB->priority = priority;
|
|
if (processCB->processStatus & OS_PROCESS_STATUS_RUNNING) {
|
|
needSched = TRUE;
|
|
}
|
|
|
|
return needSched;
|
|
}
|
|
|
|
VOID OsSchedTick(VOID)
|
|
{
|
|
Sched *sched = g_sched;
|
|
Percpu *currCpu = OsPercpuGet();
|
|
BOOL needSched = FALSE;
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
|
|
currCpu->tickStartTime = runTask->irqStartTime;
|
|
if (currCpu->responseID == OS_INVALID_VALUE) {
|
|
if (sched->swtmrScan != NULL) {
|
|
(VOID)sched->swtmrScan();
|
|
}
|
|
|
|
needSched = sched->taskScan();
|
|
|
|
if (needSched) {
|
|
LOS_MpSchedule(OS_MP_CPU_ALL);
|
|
currCpu->schedFlag |= INT_PEND_RESCH;
|
|
}
|
|
}
|
|
currCpu->schedFlag |= INT_PEND_TICK;
|
|
currCpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
|
|
}
|
|
|
|
VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask)
|
|
{
|
|
idleTask->policy = LOS_SCHED_IDLE;
|
|
idleTask->initTimeSlice = OS_SCHED_FIFO_TIMEOUT;
|
|
idleTask->timeSlice = idleTask->initTimeSlice;
|
|
OsSchedTaskEnQueue(idleTask);
|
|
}
|
|
|
|
UINT32 OsSchedSwtmrScanRegister(SchedScan func)
|
|
{
|
|
if (func == NULL) {
|
|
return LOS_NOK;
|
|
}
|
|
|
|
g_sched->swtmrScan = func;
|
|
return LOS_OK;
|
|
}
|
|
|
|
UINT32 OsSchedInit(VOID)
|
|
{
|
|
UINT16 index, pri;
|
|
UINT32 ret;
|
|
|
|
g_sched = (Sched *)LOS_MemAlloc(m_aucSysMem0, sizeof(Sched));
|
|
if (g_sched == NULL) {
|
|
return LOS_ERRNO_TSK_NO_MEMORY;
|
|
}
|
|
|
|
(VOID)memset_s(g_sched, sizeof(Sched), 0, sizeof(Sched));
|
|
|
|
for (index = 0; index < OS_PRIORITY_QUEUE_NUM; index++) {
|
|
SchedQueue *queueList = &g_sched->queueList[index];
|
|
LOS_DL_LIST *priList = &queueList->priQueueList[0];
|
|
for (pri = 0; pri < OS_PRIORITY_QUEUE_NUM; pri++) {
|
|
LOS_ListInit(&priList[pri]);
|
|
}
|
|
}
|
|
|
|
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
|
|
Percpu *cpu = OsPercpuGetByID(index);
|
|
ret = OsSortLinkInit(&cpu->taskSortLink);
|
|
if (ret != LOS_OK) {
|
|
return LOS_ERRNO_TSK_NO_MEMORY;
|
|
}
|
|
cpu->responseTime = OS_SCHED_MAX_RESPONSE_TIME;
|
|
LOS_SpinInit(&cpu->taskSortLinkSpin);
|
|
LOS_SpinInit(&cpu->swtmrSortLinkSpin);
|
|
}
|
|
|
|
g_sched->taskScan = OsSchedScanTimerList;
|
|
|
|
#ifdef LOSCFG_SCHED_TICK_DEBUG
|
|
ret = OsSchedDebugInit();
|
|
if (ret != LOS_OK) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
return LOS_OK;
|
|
}
|
|
|
|
STATIC LosTaskCB *OsGetTopTask(VOID)
|
|
{
|
|
UINT32 priority, processPriority;
|
|
UINT32 bitmap;
|
|
LosTaskCB *newTask = NULL;
|
|
UINT32 processBitmap = g_sched->queueBitmap;
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
UINT32 cpuid = ArchCurrCpuid();
|
|
#endif
|
|
|
|
while (processBitmap) {
|
|
processPriority = CLZ(processBitmap);
|
|
SchedQueue *queueList = &g_sched->queueList[processPriority];
|
|
bitmap = queueList->queueBitmap;
|
|
while (bitmap) {
|
|
priority = CLZ(bitmap);
|
|
LOS_DL_LIST_FOR_EACH_ENTRY(newTask, &queueList->priQueueList[priority], LosTaskCB, pendList) {
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
if (newTask->cpuAffiMask & (1U << cpuid)) {
|
|
#endif
|
|
goto FIND_TASK;
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
}
|
|
#endif
|
|
}
|
|
bitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - priority - 1));
|
|
}
|
|
processBitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - processPriority - 1));
|
|
}
|
|
|
|
newTask = OS_TCB_FROM_TID(OsPercpuGet()->idleTaskID);
|
|
|
|
FIND_TASK:
|
|
OsSchedDeTaskQueue(newTask, OS_PCB_FROM_PID(newTask->processID));
|
|
return newTask;
|
|
}
|
|
|
|
VOID OsSchedStart(VOID)
|
|
{
|
|
UINT32 cpuid = ArchCurrCpuid();
|
|
UINT32 intSave;
|
|
|
|
SCHEDULER_LOCK(intSave);
|
|
|
|
if (cpuid == 0) {
|
|
OsTickStart();
|
|
}
|
|
|
|
LosTaskCB *newTask = OsGetTopTask();
|
|
LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);
|
|
|
|
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
|
|
newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;
|
|
newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);
|
|
|
|
OsSchedSetStartTime(HalClockGetCycles());
|
|
newTask->startTime = OsGetCurrSchedTimeCycle();
|
|
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
/*
|
|
* attention: current cpu needs to be set, in case first task deletion
|
|
* may fail because this flag mismatch with the real current cpu.
|
|
*/
|
|
newTask->currCpu = cpuid;
|
|
#endif
|
|
|
|
OsCurrTaskSet((VOID *)newTask);
|
|
|
|
/* System start schedule */
|
|
OS_SCHEDULER_SET(cpuid);
|
|
|
|
OsPercpuGet()->responseID = OS_INVALID;
|
|
OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, newTask->startTime + newTask->timeSlice, OS_INVALID);
|
|
|
|
PRINTK("cpu %d entering scheduler\n", cpuid);
|
|
OsTaskContextLoad(newTask);
|
|
}
|
|
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
VOID OsSchedToUserReleaseLock(VOID)
|
|
{
|
|
/* The scheduling lock needs to be released before returning to user mode */
|
|
LOCKDEP_CHECK_OUT(&g_taskSpin);
|
|
ArchSpinUnlock(&g_taskSpin.rawLock);
|
|
|
|
OsPercpuGet()->taskLockCnt--;
|
|
}
|
|
#endif
|
|
|
|
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
|
|
STATIC VOID OsTaskStackCheck(LosTaskCB *runTask, LosTaskCB *newTask)
|
|
{
|
|
if (!OS_STACK_MAGIC_CHECK(runTask->topOfStack)) {
|
|
LOS_Panic("CURRENT task ID: %s:%d stack overflow!\n", runTask->taskName, runTask->taskID);
|
|
}
|
|
|
|
if (((UINTPTR)(newTask->stackPointer) <= newTask->topOfStack) ||
|
|
((UINTPTR)(newTask->stackPointer) > (newTask->topOfStack + newTask->stackSize))) {
|
|
LOS_Panic("HIGHEST task ID: %s:%u SP error! StackPointer: %p TopOfStack: %p\n",
|
|
newTask->taskName, newTask->taskID, newTask->stackPointer, newTask->topOfStack);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
STATIC INLINE VOID OsSchedSwitchCheck(LosTaskCB *runTask, LosTaskCB *newTask)
|
|
{
|
|
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
|
|
OsTaskStackCheck(runTask, newTask);
|
|
#endif /* LOSCFG_BASE_CORE_TSK_MONITOR */
|
|
|
|
OsTraceTaskSchedule(newTask, runTask);
|
|
}
|
|
|
|
STATIC INLINE VOID OsSchedSwitchProcess(LosProcessCB *runProcess, LosProcessCB *newProcess)
|
|
{
|
|
runProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_DEC(runProcess->processStatus);
|
|
newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);
|
|
|
|
LOS_ASSERT(!(OS_PROCESS_GET_RUNTASK_COUNT(newProcess->processStatus) > LOSCFG_KERNEL_CORE_NUM));
|
|
if (OS_PROCESS_GET_RUNTASK_COUNT(runProcess->processStatus) == 0) {
|
|
runProcess->processStatus &= ~OS_PROCESS_STATUS_RUNNING;
|
|
}
|
|
|
|
LOS_ASSERT(!(newProcess->processStatus & OS_PROCESS_STATUS_PENDING));
|
|
newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;
|
|
|
|
#ifdef LOSCFG_KERNEL_VM
|
|
if (OsProcessIsUserMode(newProcess)) {
|
|
LOS_ArchMmuContextSwitch(&newProcess->vmSpace->archMmu);
|
|
}
|
|
#endif
|
|
|
|
OsCurrProcessSet(newProcess);
|
|
}
|
|
|
|
STATIC VOID OsSchedTaskSwicth(LosTaskCB *runTask, LosTaskCB *newTask)
|
|
{
|
|
UINT64 endTime;
|
|
|
|
OsSchedSwitchCheck(runTask, newTask);
|
|
|
|
runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;
|
|
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
|
|
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
/* mask new running task's owner processor */
|
|
runTask->currCpu = OS_TASK_INVALID_CPUID;
|
|
newTask->currCpu = ArchCurrCpuid();
|
|
#endif
|
|
|
|
OsCurrTaskSet((VOID *)newTask);
|
|
LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);
|
|
LosProcessCB *runProcess = OS_PCB_FROM_PID(runTask->processID);
|
|
if (runProcess != newProcess) {
|
|
OsSchedSwitchProcess(runProcess, newProcess);
|
|
}
|
|
|
|
if (OsProcessIsUserMode(newProcess)) {
|
|
OsCurrUserTaskSet(newTask->userArea);
|
|
}
|
|
|
|
#ifdef LOSCFG_KERNEL_CPUP
|
|
OsCpupCycleEndStart(runTask->taskID, newTask->taskID);
|
|
#endif
|
|
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
UINT64 waitStartTime = newTask->startTime;
|
|
#endif
|
|
if (runTask->taskStatus & OS_TASK_STATUS_READY) {
|
|
/* When a thread enters the ready queue, its slice of time is updated */
|
|
newTask->startTime = runTask->startTime;
|
|
} else {
|
|
/* The currently running task is blocked */
|
|
newTask->startTime = OsGetCurrSchedTimeCycle();
|
|
/* The task is in a blocking state and needs to update its time slice before pend */
|
|
OsTimeSliceUpdate(runTask, newTask->startTime);
|
|
|
|
if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
|
|
OsAdd2SortLink(&runTask->sortList, runTask->startTime, runTask->waitTimes, OS_SORT_LINK_TASK);
|
|
}
|
|
}
|
|
|
|
if (newTask->policy == LOS_SCHED_RR) {
|
|
endTime = newTask->startTime + newTask->timeSlice;
|
|
} else {
|
|
endTime = OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION;
|
|
}
|
|
OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, endTime, runTask->taskID);
|
|
|
|
#ifdef LOSCFG_SCHED_DEBUG
|
|
newTask->schedStat.waitSchedTime += newTask->startTime - waitStartTime;
|
|
newTask->schedStat.waitSchedCount++;
|
|
runTask->schedStat.runTime = runTask->schedStat.allRuntime;
|
|
runTask->schedStat.switchCount++;
|
|
#endif
|
|
/* do the task context switch */
|
|
OsTaskSchedule(newTask, runTask);
|
|
}
|
|
|
|
VOID OsSchedIrqEndCheckNeedSched(VOID)
|
|
{
|
|
Percpu *percpu = OsPercpuGet();
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
|
|
OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle());
|
|
if (runTask->timeSlice <= OS_TIME_SLICE_MIN) {
|
|
percpu->schedFlag |= INT_PEND_RESCH;
|
|
}
|
|
|
|
if (OsPreemptable() && (percpu->schedFlag & INT_PEND_RESCH)) {
|
|
percpu->schedFlag &= ~INT_PEND_RESCH;
|
|
|
|
LOS_SpinLock(&g_taskSpin);
|
|
|
|
OsSchedTaskEnQueue(runTask);
|
|
|
|
LosTaskCB *newTask = OsGetTopTask();
|
|
if (runTask != newTask) {
|
|
OsSchedTaskSwicth(runTask, newTask);
|
|
LOS_SpinUnlock(&g_taskSpin);
|
|
return;
|
|
}
|
|
|
|
LOS_SpinUnlock(&g_taskSpin);
|
|
}
|
|
|
|
if (percpu->schedFlag & INT_PEND_TICK) {
|
|
OsSchedUpdateExpireTime(runTask->startTime);
|
|
}
|
|
}
|
|
|
|
VOID OsSchedResched(VOID)
|
|
{
|
|
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
LOS_ASSERT(OsPercpuGet()->taskLockCnt == 1);
|
|
#else
|
|
LOS_ASSERT(OsPercpuGet()->taskLockCnt == 0);
|
|
#endif
|
|
|
|
OsPercpuGet()->schedFlag &= ~INT_PEND_RESCH;
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
LosTaskCB *newTask = OsGetTopTask();
|
|
if (runTask == newTask) {
|
|
return;
|
|
}
|
|
|
|
OsSchedTaskSwicth(runTask, newTask);
|
|
}
|
|
|
|
VOID LOS_Schedule(VOID)
|
|
{
|
|
UINT32 intSave;
|
|
LosTaskCB *runTask = OsCurrTaskGet();
|
|
|
|
if (OS_INT_ACTIVE) {
|
|
OsPercpuGet()->schedFlag |= INT_PEND_RESCH;
|
|
return;
|
|
}
|
|
|
|
if (!OsPreemptable()) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* trigger schedule in task will also do the slice check
|
|
* if neccessary, it will give up the timeslice more in time.
|
|
* otherwhise, there's no other side effects.
|
|
*/
|
|
SCHEDULER_LOCK(intSave);
|
|
|
|
OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle());
|
|
|
|
/* add run task back to ready queue */
|
|
OsSchedTaskEnQueue(runTask);
|
|
|
|
/* reschedule to new thread */
|
|
OsSchedResched();
|
|
|
|
SCHEDULER_UNLOCK(intSave);
|
|
}
|
|
|
|
STATIC INLINE LOS_DL_LIST *OsSchedLockPendFindPosSub(const LosTaskCB *runTask, const LOS_DL_LIST *lockList)
|
|
{
|
|
LosTaskCB *pendedTask = NULL;
|
|
LOS_DL_LIST *node = NULL;
|
|
|
|
LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, lockList, LosTaskCB, pendList) {
|
|
if (pendedTask->priority < runTask->priority) {
|
|
continue;
|
|
} else if (pendedTask->priority > runTask->priority) {
|
|
node = &pendedTask->pendList;
|
|
break;
|
|
} else {
|
|
node = pendedTask->pendList.pstNext;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
LOS_DL_LIST *OsSchedLockPendFindPos(const LosTaskCB *runTask, LOS_DL_LIST *lockList)
|
|
{
|
|
LOS_DL_LIST *node = NULL;
|
|
|
|
if (LOS_ListEmpty(lockList)) {
|
|
node = lockList;
|
|
} else {
|
|
LosTaskCB *pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(lockList));
|
|
LosTaskCB *pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(lockList));
|
|
if (pendedTask1->priority > runTask->priority) {
|
|
node = lockList->pstNext;
|
|
} else if (pendedTask2->priority <= runTask->priority) {
|
|
node = lockList;
|
|
} else {
|
|
node = OsSchedLockPendFindPosSub(runTask, lockList);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|