참고 : 핵심 오픈 소스 모호성 분석을 기반으로 공식 소스 [ kernel_liteos_a ] 공식 문서 [ 문서 ] 참조 문서 [ Huawei LiteOS ]
작성자 : Hong Meng 핵심 애호가는 모호성 커널, 업데이트 블로그를 계속 연구하므로 계속 지켜봐 주시기 바랍니다. 내용은 개인적인 견해를 나타내며 오류는 환영하며 모든 사람이 수정하고 개선 할 수 있습니다. 이 시리즈의 모든 기사 는 Hongmeng 시스템 (일반 카탈로그) 의 소스 코드 분석 을보기 위해 입력됩니다.
목차
틱 트리거 스케줄링 외에 어떤 다른 상황이 스케줄링을 트리거합니까?
클럭 관리 모듈은 매우 간단하지만 커널에서 가장 중요한 코드 세그먼트 인 OsTickHandler ()가 있는데, 이것은 JAVA 타이밍 태스크로 이해할 수 있지만 시스템 커널의 타이머입니다. Hongmeng은 현재 경량 커널 라이트 OS (LOS)를 열고 있으므로 틱 빈도가 너무 높지 않습니다.
자세한 내용은 코드를 참조하십시오 : los_tick.c los_timeslice.c
얼마나 자주 틱합니까?
/**
* @ingroup los_config
* Number of Ticks in one second
*/
#ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 100 //*kfy 默认每秒100次触发,当然这是可以改的
#endif
초당 100 틱, 즉, 클럭 인터럽트 핸들러는 초당 100 번 호출되고 시간 슬라이스 단위는 10ms입니다.
프로세스가 작업을 실행하는 데 얼마나 많은 시간이 할당됩니까? 답은 2 개의 타임 슬라이스, 즉 20ms입니다.
/**
* @ingroup los_config
* Longest execution time of tasks with the same priorities
*/
#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2
#endif
/**
* @ingroup los_process
* Hold the time slice process
*/
#define OS_PROCESS_SCHED_RR_INTERVAL LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
다 사용하면 재배포가 가능하지만 한 번에 2 개의 타임 슬라이스 만 주어집니다. 상세 코드 : OsSchedResched (VOID)
VOID OsSchedResched(VOID)
{
LosTaskCB *runTask = NULL;
LosTaskCB *newTask = NULL;
LosProcessCB *runProcess = NULL;
LosProcessCB *newProcess = NULL;
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
if (!OsPreemptableInSched()) {
return;
}
runTask = OsCurrTaskGet();
newTask = OsGetTopTask();
/* always be able to get one task */
LOS_ASSERT(newTask != NULL);
if (runTask == newTask) {
return;
}
runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
runProcess = OS_PCB_FROM_PID(runTask->processID);
newProcess = OS_PCB_FROM_PID(newTask->processID);
OsSchedSwitchProcess(runProcess, newProcess);
#if (LOSCFG_KERNEL_SMP == YES)
/* mask new running task's owner processor */
runTask->currCpu = OS_TASK_INVALID_CPUID;
newTask->currCpu = ArchCurrCpuid();
#endif
(VOID)OsTaskSwitchCheck(runTask, newTask);
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
OsSchedStatistics(runTask, newTask);
#endif
if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {
newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT; //只给两个时间片
}
OsCurrTaskSet((VOID*)newTask);
if (OsProcessIsUserMode(newProcess)) {
OsCurrUserTaskSet(newTask->userArea);
}
PRINT_TRACE("cpu%d run process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x ->\n"
" new process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x!\n",
ArchCurrCpuid(),
runProcess->processName, runProcess->processID, runProcess->processStatus,
runProcess->threadScheduleMap, runTask->taskName, runTask->taskID, runTask->taskStatus,
newProcess->processName, newProcess->processID, newProcess->processStatus,
newProcess->threadScheduleMap, newTask->taskName, newTask->taskID, newTask->taskStatus);
/* do the task context switch */
OsTaskSchedule(newTask, runTask);
}
틱 콜백 기능은 어디에서 설정합니까?
메인에서 틱 초기화 및 인터럽트 서비스 프로그램 등록을 확인할 수 있습니다.
// 中断处理函数
VOID OsTickEntry(VOID)
{
OsTickHandler(); //最最关键函数
/* clear private timer */
g_privateTimer->intStatus = 0x01;
}
// 由 main 函数调用,注册中断处理函数 OsTickEntry
VOID HalClockInit(VOID)
{
UINT32 ret;
ret = LOS_HwiCreate(PRVTIMER_INT_NUM, 0xa0, 0, OsTickEntry, NULL);
if (ret != LOS_OK) {
PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__, ret);
}
}
OsTickHandler는 타임 슬라이스 검사 및 작업 스캔을 완료하는 틱 인터럽트 핸들러입니다.
/*
* Description : Tick interruption handler
*/
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
UINT32 intSave;
TICK_LOCK(intSave);
g_tickCount[ArchCurrCpuid()]++;
TICK_UNLOCK(intSave);
#ifdef LOSCFG_KERNEL_VDSO
OsUpdateVdsoTimeval();
#endif
#ifdef LOSCFG_KERNEL_TICKLESS
OsTickIrqFlagSet(OsTicklessFlagGet());
#endif
#if (LOSCFG_BASE_CORE_TICK_HW_TIME == YES)
HalClockIrqClear(); /* diff from every platform */
#endif
OsTimesliceCheck();
OsTaskScan(); /* task timeout scan */
#if (LOSCFG_BASE_CORE_SWTMR == YES)
OsSwtmrScan();
#endif
}
LITE_OS_SEC_TEXT VOID OsTimesliceCheck(VOID)
{
LosTaskCB *runTask = NULL;
LosProcessCB *runProcess = OsCurrProcessGet();
if (runProcess->policy != LOS_SCHED_RR) {
goto SCHED_TASK;
}
if (runProcess->timeSlice != 0) {
runProcess->timeSlice--;//进程时间片减少一次
if (runProcess->timeSlice == 0) {
LOS_Schedule();//进程时间片用完,发起调度
}
}
SCHED_TASK:
runTask = OsCurrTaskGet();
if (runTask->policy != LOS_SCHED_RR) {
return;
}
if (runTask->timeSlice != 0) {
runTask->timeSlice--;//对应任务时间片也减少一次
if (runTask->timeSlice == 0) {
LOS_Schedule();
}
}
}
OsTaskScan ()
OsTaskScan ()은 작업의 상태를 지속적으로 확인하고 작업이있을 때 실행하며, 그것이 프로세스의 질서있는 실행의 원천이라고해도 과언이 아닙니다!
LITE_OS_SEC_TEXT VOID OsTaskScan(VOID)
{
SortLinkList *sortList = NULL;
LosTaskCB *taskCB = NULL;
BOOL needSchedule = FALSE;
UINT16 tempStatus;
LOS_DL_LIST *listObject = NULL;
SortLinkAttribute *taskSortLink = NULL;
taskSortLink = &OsPercpuGet()->taskSortLink;
taskSortLink->cursor = (taskSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
listObject = taskSortLink->sortLink + taskSortLink->cursor;
/*
* 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(&g_taskSpin);
if (LOS_ListEmpty(listObject)) {
LOS_SpinUnlock(&g_taskSpin);
return;
}
sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
ROLLNUM_DEC(sortList->idxRollNum);
while (ROLLNUM(sortList->idxRollNum) == 0) {
LOS_ListDelete(&sortList->sortLinkNode);
taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);
taskCB->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
tempStatus = taskCB->taskStatus;
if (tempStatus & OS_TASK_STATUS_PEND) {
taskCB->taskStatus &= ~OS_TASK_STATUS_PEND;
#if (LOSCFG_KERNEL_LITEIPC == YES)
taskCB->ipcStatus &= ~IPC_THREAD_STATUS_PEND;
#endif
taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT;
LOS_ListDelete(&taskCB->pendList);
taskCB->taskSem = NULL;
taskCB->taskMux = NULL;
} else {
taskCB->taskStatus &= ~OS_TASK_STATUS_DELAY;
}
if (!(tempStatus & OS_TASK_STATUS_SUSPEND)) {
OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, OS_PROCESS_STATUS_PEND);
needSchedule = TRUE;
}
if (LOS_ListEmpty(listObject)) {
break;
}
sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
}
LOS_SpinUnlock(&g_taskSpin);
if (needSchedule != FALSE) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
}
틱 트리거 스케줄링 외에 어떤 다른 상황이 스케줄링을 트리거합니까?
생각해 보시면 댓글란에 메시지를 남겨주세요.이 시리즈의 더 많은 기사는 Hongmeng 시스템 소스 코드 분석 (일반 카탈로그)에 들어갈 것 입니다.