From 93e3b39fa34b8408ab3e42ad58083a83af5357c8 Mon Sep 17 00:00:00 2001 From: ruanjiangongcheng <1403296320@qq.com> Date: Mon, 27 Nov 2023 20:00:52 +0800 Subject: [PATCH] 1 --- DOCX/软件阅读报告.docx | 0 core/los_bitmap.c | 138 +++ core/los_process.c | 2023 +++++++++++++++++++++++++++++++++ core/los_smp.c | 84 ++ core/los_swtmr.c | 536 +++++++++ core/los_sys.c | 72 ++ core/los_task.c | 1691 +++++++++++++++++++++++++++ core/los_tick.c | 66 ++ sched/sched_sq/los_sched.c | 1170 +++++++++++++++++++ sched/sched_sq/los_sortlink.c | 232 ++++ 10 files changed, 6012 insertions(+) create mode 100644 DOCX/软件阅读报告.docx create mode 100644 core/los_bitmap.c create mode 100644 core/los_process.c create mode 100644 core/los_smp.c create mode 100644 core/los_swtmr.c create mode 100644 core/los_sys.c create mode 100644 core/los_task.c create mode 100644 core/los_tick.c create mode 100644 sched/sched_sq/los_sched.c create mode 100644 sched/sched_sq/los_sortlink.c diff --git a/DOCX/软件阅读报告.docx b/DOCX/软件阅读报告.docx new file mode 100644 index 0000000..e69de29 diff --git a/core/los_bitmap.c b/core/los_bitmap.c new file mode 100644 index 0000000..4e8b860 --- /dev/null +++ b/core/los_bitmap.c @@ -0,0 +1,138 @@ +/* + * 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_bitmap.h" +#include "los_printf.h" +#include "los_toolchain.h" + + +#define OS_BITMAP_MASK 0x1FU +#define OS_BITMAP_WORD_MASK ~0UL + +/* find first zero bit starting from LSB */ +STATIC INLINE UINT16 Ffz(UINTPTR x) +{ + return __builtin_ffsl(~x) - 1; +} + +VOID LOS_BitmapSet(UINT32 *bitmap, UINT16 pos) +{ + if (bitmap == NULL) { + return; + } + + *bitmap |= 1U << (pos & OS_BITMAP_MASK); +} + +VOID LOS_BitmapClr(UINT32 *bitmap, UINT16 pos) +{ + if (bitmap == NULL) { + return; + } + + *bitmap &= ~(1U << (pos & OS_BITMAP_MASK)); +} + +UINT16 LOS_HighBitGet(UINT32 bitmap) +{ + if (bitmap == 0) { + return LOS_INVALID_BIT_INDEX; + } + + return (OS_BITMAP_MASK - CLZ(bitmap)); +} + +UINT16 LOS_LowBitGet(UINT32 bitmap) +{ + if (bitmap == 0) { + return LOS_INVALID_BIT_INDEX; + } + + return CTZ(bitmap); +} + +VOID LOS_BitmapSetNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsSet) +{ + UINTPTR *p = bitmap + BITMAP_WORD(start); + const UINT32 size = start + numsSet; + UINT16 bitsToSet = BITMAP_BITS_PER_WORD - (start % BITMAP_BITS_PER_WORD); + UINTPTR maskToSet = BITMAP_FIRST_WORD_MASK(start); + + while (numsSet > bitsToSet) { + *p |= maskToSet; + numsSet -= bitsToSet; + bitsToSet = BITMAP_BITS_PER_WORD; + maskToSet = OS_BITMAP_WORD_MASK; + p++; + } + if (numsSet) { + maskToSet &= BITMAP_LAST_WORD_MASK(size); + *p |= maskToSet; + } +} + +VOID LOS_BitmapClrNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsClear) +{ + UINTPTR *p = bitmap + BITMAP_WORD(start); + const UINT32 size = start + numsClear; + UINT16 bitsToClear = BITMAP_BITS_PER_WORD - (start % BITMAP_BITS_PER_WORD); + UINTPTR maskToClear = BITMAP_FIRST_WORD_MASK(start); + + while (numsClear >= bitsToClear) { + *p &= ~maskToClear; + numsClear -= bitsToClear; + bitsToClear = BITMAP_BITS_PER_WORD; + maskToClear = OS_BITMAP_WORD_MASK; + p++; + } + if (numsClear) { + maskToClear &= BITMAP_LAST_WORD_MASK(size); + *p &= ~maskToClear; + } +} + +INT32 LOS_BitmapFfz(UINTPTR *bitmap, UINT32 numBits) +{ + INT32 bit, i; + + for (i = 0; i < BITMAP_NUM_WORDS(numBits); i++) { + if (bitmap[i] == OS_BITMAP_WORD_MASK) { + continue; + } + bit = i * BITMAP_BITS_PER_WORD + Ffz(bitmap[i]); + if (bit < numBits) { + return bit; + } + return -1; + } + return -1; +} + diff --git a/core/los_process.c b/core/los_process.c new file mode 100644 index 0000000..61b463d --- /dev/null +++ b/core/los_process.c @@ -0,0 +1,2023 @@ +/* + * 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_process_pri.h" +#include "los_sched_pri.h" +#include "los_task_pri.h" +#include "los_hw_pri.h" +#include "los_sem_pri.h" +#include "los_mp.h" +#include "los_exc.h" +#include "asm/page.h" +#ifdef LOSCFG_FS_VFS +#include "fs/fd_table.h" +#include "fs/fs_operation.h" +#endif +#include "time.h" +#include "user_copy.h" +#include "los_signal.h" +#ifdef LOSCFG_SECURITY_VID +#include "vid_api.h" +#endif +#ifdef LOSCFG_SECURITY_CAPABILITY +#include "capability_api.h" +#endif +#include "los_swtmr_pri.h" +#include "los_vm_map.h" +#include "los_vm_phys.h" +#include "los_vm_syscall.h" + + +LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL; +LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess; +LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecycleList; +LITE_OS_SEC_BSS UINT32 g_userInitProcess = OS_INVALID_VALUE; +LITE_OS_SEC_BSS UINT32 g_kernelInitProcess = OS_INVALID_VALUE; +LITE_OS_SEC_BSS UINT32 g_kernelIdleProcess = OS_INVALID_VALUE; +LITE_OS_SEC_BSS UINT32 g_processMaxNum; +LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL; + +STATIC INLINE VOID OsInsertPCBToFreeList(LosProcessCB *processCB) +{ + UINT32 pid = processCB->processID; + (VOID)memset_s(processCB, sizeof(LosProcessCB), 0, sizeof(LosProcessCB)); + processCB->processID = pid; + processCB->processStatus = OS_PROCESS_FLAG_UNUSED; + processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID; + LOS_ListTailInsert(&g_freeProcess, &processCB->pendList); +} + +STATIC ProcessGroup *OsCreateProcessGroup(UINT32 pid) +{ + LosProcessCB *processCB = NULL; + ProcessGroup *group = LOS_MemAlloc(m_aucSysMem1, sizeof(ProcessGroup)); + if (group == NULL) { + return NULL; + } + + group->groupID = pid; + LOS_ListInit(&group->processList); + LOS_ListInit(&group->exitProcessList); + + processCB = OS_PCB_FROM_PID(pid); + LOS_ListTailInsert(&group->processList, &processCB->subordinateGroupList); + processCB->group = group; + processCB->processStatus |= OS_PROCESS_FLAG_GROUP_LEADER; + if (g_processGroup != NULL) { + LOS_ListTailInsert(&g_processGroup->groupList, &group->groupList); + } + + return group; +} + +STATIC VOID OsExitProcessGroup(LosProcessCB *processCB, ProcessGroup **group) +{ + LosProcessCB *groupProcessCB = OS_PCB_FROM_PID(processCB->group->groupID); + + LOS_ListDelete(&processCB->subordinateGroupList); + if (LOS_ListEmpty(&processCB->group->processList) && LOS_ListEmpty(&processCB->group->exitProcessList)) { + LOS_ListDelete(&processCB->group->groupList); + groupProcessCB->processStatus &= ~OS_PROCESS_FLAG_GROUP_LEADER; + *group = processCB->group; + if (OsProcessIsUnused(groupProcessCB) && !(groupProcessCB->processStatus & OS_PROCESS_FLAG_EXIT)) { + LOS_ListDelete(&groupProcessCB->pendList); + OsInsertPCBToFreeList(groupProcessCB); + } + } + + processCB->group = NULL; +} + +STATIC ProcessGroup *OsFindProcessGroup(UINT32 gid) +{ + ProcessGroup *group = NULL; + if (g_processGroup->groupID == gid) { + return g_processGroup; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(group, &g_processGroup->groupList, ProcessGroup, groupList) { + if (group->groupID == gid) { + return group; + } + } + + PRINT_INFO("%s is find group : %u failed!\n", __FUNCTION__, gid); + return NULL; +} + +STATIC INT32 OsSendSignalToSpecifyProcessGroup(ProcessGroup *group, siginfo_t *info, INT32 permission) +{ + INT32 ret, success, err; + LosProcessCB *childCB = NULL; + + success = 0; + ret = -LOS_ESRCH; + LOS_DL_LIST_FOR_EACH_ENTRY(childCB, &(group->processList), LosProcessCB, subordinateGroupList) { + if (childCB->processID == 0) { + continue; + } + + err = OsDispatch(childCB->processID, info, permission); + success |= !err; + ret = err; + } + /* At least one success. */ + return success ? LOS_OK : ret; +} + +LITE_OS_SEC_TEXT INT32 OsSendSignalToAllProcess(siginfo_t *info, INT32 permission) +{ + INT32 ret, success, err; + ProcessGroup *group = NULL; + + success = 0; + err = OsSendSignalToSpecifyProcessGroup(g_processGroup, info, permission); + success |= !err; + ret = err; + /* all processes group */ + LOS_DL_LIST_FOR_EACH_ENTRY(group, &g_processGroup->groupList, ProcessGroup, groupList) { + /* all processes in the process group. */ + err = OsSendSignalToSpecifyProcessGroup(group, info, permission); + success |= !err; + ret = err; + } + return success ? LOS_OK : ret; +} + +LITE_OS_SEC_TEXT INT32 OsSendSignalToProcessGroup(INT32 pid, siginfo_t *info, INT32 permission) +{ + ProcessGroup *group = NULL; + /* Send SIG to all processes in process group PGRP. + If PGRP is zero, send SIG to all processes in + the current process's process group. */ + group = OsFindProcessGroup(pid ? -pid : LOS_GetCurrProcessGroupID()); + if (group == NULL) { + return -LOS_ESRCH; + } + /* all processes in the process group. */ + return OsSendSignalToSpecifyProcessGroup(group, info, permission); +} + +STATIC LosProcessCB *OsFindGroupExitProcess(ProcessGroup *group, INT32 pid) +{ + LosProcessCB *childCB = NULL; + + LOS_DL_LIST_FOR_EACH_ENTRY(childCB, &(group->exitProcessList), LosProcessCB, subordinateGroupList) { + if ((childCB->processID == pid) || (pid == OS_INVALID_VALUE)) { + return childCB; + } + } + + PRINT_INFO("%s find exit process : %d failed in group : %u\n", __FUNCTION__, pid, group->groupID); + return NULL; +} + +STATIC UINT32 OsFindChildProcess(const LosProcessCB *processCB, INT32 childPid) +{ + LosProcessCB *childCB = NULL; + + if (childPid < 0) { + goto ERR; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(childCB, &(processCB->childrenList), LosProcessCB, siblingList) { + if (childCB->processID == childPid) { + return LOS_OK; + } + } + +ERR: + PRINT_INFO("%s is find the child : %d failed in parent : %u\n", __FUNCTION__, childPid, processCB->processID); + return LOS_NOK; +} + +STATIC LosProcessCB *OsFindExitChildProcess(const LosProcessCB *processCB, INT32 childPid) +{ + LosProcessCB *exitChild = NULL; + + LOS_DL_LIST_FOR_EACH_ENTRY(exitChild, &(processCB->exitChildList), LosProcessCB, siblingList) { + if ((childPid == OS_INVALID_VALUE) || (exitChild->processID == childPid)) { + return exitChild; + } + } + + PRINT_INFO("%s is find the exit child : %d failed in parent : %u\n", __FUNCTION__, childPid, processCB->processID); + return NULL; +} + +VOID OsWaitWakeTask(LosTaskCB *taskCB, UINT32 wakePID) +{ + taskCB->waitID = wakePID; + OsSchedTaskWake(taskCB); +#ifdef LOSCFG_KERNEL_SMP + LOS_MpSchedule(OS_MP_CPU_ALL); +#endif +} + +STATIC BOOL OsWaitWakeSpecifiedProcess(LOS_DL_LIST *head, const LosProcessCB *processCB, LOS_DL_LIST **anyList) +{ + LOS_DL_LIST *list = head; + LosTaskCB *taskCB = NULL; + UINT32 pid = 0; + BOOL find = FALSE; + + while (list->pstNext != head) { + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(list)); + if ((taskCB->waitFlag == OS_PROCESS_WAIT_PRO) && (taskCB->waitID == processCB->processID)) { + if (pid == 0) { + pid = processCB->processID; + find = TRUE; + } else { + pid = OS_INVALID_VALUE; + } + + OsWaitWakeTask(taskCB, pid); + continue; + } + + if (taskCB->waitFlag != OS_PROCESS_WAIT_PRO) { + *anyList = list; + break; + } + list = list->pstNext; + } + + return find; +} + +STATIC VOID OsWaitCheckAndWakeParentProcess(LosProcessCB *parentCB, const LosProcessCB *processCB) +{ + LOS_DL_LIST *head = &parentCB->waitList; + LOS_DL_LIST *list = NULL; + LosTaskCB *taskCB = NULL; + BOOL findSpecified = FALSE; + + if (LOS_ListEmpty(&parentCB->waitList)) { + return; + } + + findSpecified = OsWaitWakeSpecifiedProcess(head, processCB, &list); + if (findSpecified == TRUE) { + /* No thread is waiting for any child process to finish */ + if (LOS_ListEmpty(&parentCB->waitList)) { + return; + } else if (!LOS_ListEmpty(&parentCB->childrenList)) { + /* Other child processes exist, and other threads that are waiting + * for the child to finish continue to wait + */ + return; + } + } + + /* Waiting threads are waiting for a specified child process to finish */ + if (list == NULL) { + return; + } + + /* No child processes exist and all waiting threads are awakened */ + if (findSpecified == TRUE) { + while (list->pstNext != head) { + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(list)); + OsWaitWakeTask(taskCB, OS_INVALID_VALUE); + } + return; + } + + while (list->pstNext != head) { + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(list)); + if (taskCB->waitFlag == OS_PROCESS_WAIT_GID) { + if (taskCB->waitID != processCB->group->groupID) { + list = list->pstNext; + continue; + } + } + + if (findSpecified == FALSE) { + OsWaitWakeTask(taskCB, processCB->processID); + findSpecified = TRUE; + } else { + OsWaitWakeTask(taskCB, OS_INVALID_VALUE); + } + + if (!LOS_ListEmpty(&parentCB->childrenList)) { + break; + } + } + + return; +} + +LITE_OS_SEC_TEXT VOID OsProcessResourcesToFree(LosProcessCB *processCB) +{ + if (!(processCB->processStatus & (OS_PROCESS_STATUS_INIT | OS_PROCESS_STATUS_RUNNING))) { + PRINT_ERR("The process(%d) has no permission to release process(%d) resources!\n", + OsCurrProcessGet()->processID, processCB->processID); + } + +#ifdef LOSCFG_FS_VFS + if (OsProcessIsUserMode(processCB)) { + delete_files(processCB->files); + } + processCB->files = NULL; +#endif + +#ifdef LOSCFG_SECURITY_CAPABILITY + if (processCB->user != NULL) { + (VOID)LOS_MemFree(m_aucSysMem1, processCB->user); + processCB->user = NULL; + } +#endif + + OsSwtmrRecycle(processCB->processID); + processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID; + +#ifdef LOSCFG_SECURITY_VID + if (processCB->timerIdMap.bitMap != NULL) { + VidMapDestroy(processCB); + processCB->timerIdMap.bitMap = NULL; + } +#endif + +#ifdef LOSCFG_KERNEL_LITEIPC + if (OsProcessIsUserMode(processCB)) { + LiteIpcPoolDelete(&(processCB->ipcInfo)); + (VOID)memset_s(&(processCB->ipcInfo), sizeof(ProcIpcInfo), 0, sizeof(ProcIpcInfo)); + } +#endif +} + +LITE_OS_SEC_TEXT STATIC VOID OsRecycleZombiesProcess(LosProcessCB *childCB, ProcessGroup **group) +{ + OsExitProcessGroup(childCB, group); + LOS_ListDelete(&childCB->siblingList); + if (childCB->processStatus & OS_PROCESS_STATUS_ZOMBIES) { + childCB->processStatus &= ~OS_PROCESS_STATUS_ZOMBIES; + childCB->processStatus |= OS_PROCESS_FLAG_UNUSED; + } + + LOS_ListDelete(&childCB->pendList); + if (childCB->processStatus & OS_PROCESS_FLAG_EXIT) { + LOS_ListHeadInsert(&g_processRecycleList, &childCB->pendList); + } else if (childCB->processStatus & OS_PROCESS_FLAG_GROUP_LEADER) { + LOS_ListTailInsert(&g_processRecycleList, &childCB->pendList); + } else { + OsInsertPCBToFreeList(childCB); + } +} + +STATIC VOID OsDealAliveChildProcess(LosProcessCB *processCB) +{ + UINT32 parentID; + LosProcessCB *childCB = NULL; + LosProcessCB *parentCB = NULL; + LOS_DL_LIST *nextList = NULL; + LOS_DL_LIST *childHead = NULL; + + if (!LOS_ListEmpty(&processCB->childrenList)) { + childHead = processCB->childrenList.pstNext; + LOS_ListDelete(&(processCB->childrenList)); + if (OsProcessIsUserMode(processCB)) { + parentID = g_userInitProcess; + } else { + parentID = g_kernelInitProcess; + } + + for (nextList = childHead; ;) { + childCB = OS_PCB_FROM_SIBLIST(nextList); + childCB->parentProcessID = parentID; + nextList = nextList->pstNext; + if (nextList == childHead) { + break; + } + } + + parentCB = OS_PCB_FROM_PID(parentID); + LOS_ListTailInsertList(&parentCB->childrenList, childHead); + } + + return; +} + +STATIC VOID OsChildProcessResourcesFree(const LosProcessCB *processCB) +{ + LosProcessCB *childCB = NULL; + ProcessGroup *group = NULL; + + while (!LOS_ListEmpty(&((LosProcessCB *)processCB)->exitChildList)) { + childCB = LOS_DL_LIST_ENTRY(processCB->exitChildList.pstNext, LosProcessCB, siblingList); + OsRecycleZombiesProcess(childCB, &group); + (VOID)LOS_MemFree(m_aucSysMem1, group); + } +} + +STATIC VOID OsProcessNaturalExit(LosTaskCB *runTask, UINT32 status) +{ + LosProcessCB *processCB = OS_PCB_FROM_PID(runTask->processID); + LosProcessCB *parentCB = NULL; + + LOS_ASSERT(processCB->processStatus & OS_PROCESS_STATUS_RUNNING); + + OsChildProcessResourcesFree(processCB); + + /* is a child process */ + if (processCB->parentProcessID != OS_INVALID_VALUE) { + parentCB = OS_PCB_FROM_PID(processCB->parentProcessID); + LOS_ListDelete(&processCB->siblingList); + if (!OsProcessExitCodeSignalIsSet(processCB)) { + OsProcessExitCodeSet(processCB, status); + } + LOS_ListTailInsert(&parentCB->exitChildList, &processCB->siblingList); + LOS_ListDelete(&processCB->subordinateGroupList); + LOS_ListTailInsert(&processCB->group->exitProcessList, &processCB->subordinateGroupList); + + OsWaitCheckAndWakeParentProcess(parentCB, processCB); + + OsDealAliveChildProcess(processCB); + + processCB->processStatus |= OS_PROCESS_STATUS_ZOMBIES; + +#ifdef LOSCFG_KERNEL_VM + (VOID)OsKill(processCB->parentProcessID, SIGCHLD, OS_KERNEL_KILL_PERMISSION); +#endif + LOS_ListHeadInsert(&g_processRecycleList, &processCB->pendList); + OsRunTaskToDelete(runTask); + return; + } + + LOS_Panic("pid : %u is the root process exit!\n", processCB->processID); + return; +} + +STATIC UINT32 OsProcessInit(VOID) +{ + UINT32 index; + UINT32 size; + + g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT; + size = g_processMaxNum * sizeof(LosProcessCB); + + g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size); + if (g_processCBArray == NULL) { + return LOS_NOK; + } + (VOID)memset_s(g_processCBArray, size, 0, size); + + LOS_ListInit(&g_freeProcess); + LOS_ListInit(&g_processRecycleList); + + for (index = 0; index < g_processMaxNum; index++) { + g_processCBArray[index].processID = index; + g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED; + LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList); + } + + g_kernelIdleProcess = 0; /* 0: The idle process ID of the kernel-mode process is fixed at 0 */ + LOS_ListDelete(&OS_PCB_FROM_PID(g_kernelIdleProcess)->pendList); + + g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 */ + LOS_ListDelete(&OS_PCB_FROM_PID(g_userInitProcess)->pendList); + + g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 */ + LOS_ListDelete(&OS_PCB_FROM_PID(g_kernelInitProcess)->pendList); + + return LOS_OK; +} + +LITE_OS_SEC_TEXT VOID OsProcessCBRecycleToFree(VOID) +{ + UINT32 intSave; + LosProcessCB *processCB = NULL; + + SCHEDULER_LOCK(intSave); + while (!LOS_ListEmpty(&g_processRecycleList)) { + processCB = OS_PCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_processRecycleList)); + if (!(processCB->processStatus & OS_PROCESS_FLAG_EXIT)) { + break; + } + SCHEDULER_UNLOCK(intSave); + + OsTaskCBRecycleToFree(); + + SCHEDULER_LOCK(intSave); + processCB->processStatus &= ~OS_PROCESS_FLAG_EXIT; +#ifdef LOSCFG_KERNEL_VM + LosVmSpace *space = NULL; + if (OsProcessIsUserMode(processCB)) { + space = processCB->vmSpace; + } + processCB->vmSpace = NULL; +#endif + /* OS_PROCESS_FLAG_GROUP_LEADER: The lead process group cannot be recycled without destroying the PCB. + * !OS_PROCESS_FLAG_UNUSED: Parent process does not reclaim child process resources. + */ + LOS_ListDelete(&processCB->pendList); + if ((processCB->processStatus & OS_PROCESS_FLAG_GROUP_LEADER) || + (processCB->processStatus & OS_PROCESS_STATUS_ZOMBIES)) { + LOS_ListTailInsert(&g_processRecycleList, &processCB->pendList); + } else { + /* Clear the bottom 4 bits of process status */ + OsInsertPCBToFreeList(processCB); + } + SCHEDULER_UNLOCK(intSave); +#ifdef LOSCFG_KERNEL_VM + (VOID)LOS_VmSpaceFree(space); +#endif + SCHEDULER_LOCK(intSave); + } + + SCHEDULER_UNLOCK(intSave); +} + +STATIC VOID OsDeInitPCB(LosProcessCB *processCB) +{ + UINT32 intSave; + ProcessGroup *group = NULL; + + if (processCB == NULL) { + return; + } + + OsProcessResourcesToFree(processCB); + + SCHEDULER_LOCK(intSave); + if (processCB->parentProcessID != OS_INVALID_VALUE) { + LOS_ListDelete(&processCB->siblingList); + processCB->parentProcessID = OS_INVALID_VALUE; + } + + if (processCB->group != NULL) { + OsExitProcessGroup(processCB, &group); + } + + processCB->processStatus &= ~OS_PROCESS_STATUS_INIT; + processCB->processStatus |= OS_PROCESS_FLAG_EXIT; + LOS_ListHeadInsert(&g_processRecycleList, &processCB->pendList); + SCHEDULER_UNLOCK(intSave); + + (VOID)LOS_MemFree(m_aucSysMem1, group); + OsWriteResourceEvent(OS_RESOURCE_EVENT_FREE); + return; +} + +UINT32 OsSetProcessName(LosProcessCB *processCB, const CHAR *name) +{ + errno_t errRet; + + if (processCB == NULL) { + return LOS_EINVAL; + } + + if (name != NULL) { + errRet = strncpy_s(processCB->processName, OS_PCB_NAME_LEN, name, OS_PCB_NAME_LEN - 1); + if (errRet == EOK) { + return LOS_OK; + } + } + + switch (processCB->processMode) { + case OS_KERNEL_MODE: + errRet = snprintf_s(processCB->processName, OS_PCB_NAME_LEN, OS_PCB_NAME_LEN - 1, + "KerProcess%u", processCB->processID); + break; + default: + errRet = snprintf_s(processCB->processName, OS_PCB_NAME_LEN, OS_PCB_NAME_LEN - 1, + "UserProcess%u", processCB->processID); + break; + } + + if (errRet < 0) { + return LOS_NOK; + } + return LOS_OK; +} + +STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, UINT16 priority, const CHAR *name) +{ + processCB->processMode = mode; + processCB->processStatus = OS_PROCESS_STATUS_INIT; + processCB->parentProcessID = OS_INVALID_VALUE; + processCB->threadGroupID = OS_INVALID_VALUE; + processCB->priority = priority; + processCB->umask = OS_PROCESS_DEFAULT_UMASK; + processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID; + + LOS_ListInit(&processCB->threadSiblingList); + LOS_ListInit(&processCB->childrenList); + LOS_ListInit(&processCB->exitChildList); + LOS_ListInit(&(processCB->waitList)); + +#ifdef LOSCFG_KERNEL_VM + if (OsProcessIsUserMode(processCB)) { + processCB->vmSpace = OsCreateUserVmSpace(); + if (processCB->vmSpace == NULL) { + processCB->processStatus = OS_PROCESS_FLAG_UNUSED; + return LOS_ENOMEM; + } + } else { + processCB->vmSpace = LOS_GetKVmSpace(); + } +#endif + +#ifdef LOSCFG_SECURITY_VID + status_t status = VidMapListInit(processCB); + if (status != LOS_OK) { + return LOS_ENOMEM; + } +#endif +#ifdef LOSCFG_SECURITY_CAPABILITY + OsInitCapability(processCB); +#endif + + if (OsSetProcessName(processCB, name) != LOS_OK) { + return LOS_ENOMEM; + } + + return LOS_OK; +} + +#ifdef LOSCFG_SECURITY_CAPABILITY +STATIC User *OsCreateUser(UINT32 userID, UINT32 gid, UINT32 size) +{ + User *user = LOS_MemAlloc(m_aucSysMem1, sizeof(User) + (size - 1) * sizeof(UINT32)); + if (user == NULL) { + return NULL; + } + + user->userID = userID; + user->effUserID = userID; + user->gid = gid; + user->effGid = gid; + user->groupNumber = size; + user->groups[0] = gid; + return user; +} + +LITE_OS_SEC_TEXT BOOL LOS_CheckInGroups(UINT32 gid) +{ + UINT32 intSave; + UINT32 count; + User *user = NULL; + + SCHEDULER_LOCK(intSave); + user = OsCurrUserGet(); + for (count = 0; count < user->groupNumber; count++) { + if (user->groups[count] == gid) { + SCHEDULER_UNLOCK(intSave); + return TRUE; + } + } + + SCHEDULER_UNLOCK(intSave); + return FALSE; +} +#endif + +LITE_OS_SEC_TEXT INT32 LOS_GetUserID(VOID) +{ +#ifdef LOSCFG_SECURITY_CAPABILITY + UINT32 intSave; + INT32 uid; + + SCHEDULER_LOCK(intSave); + uid = (INT32)OsCurrUserGet()->userID; + SCHEDULER_UNLOCK(intSave); + return uid; +#else + return 0; +#endif +} + +LITE_OS_SEC_TEXT INT32 LOS_GetGroupID(VOID) +{ +#ifdef LOSCFG_SECURITY_CAPABILITY + UINT32 intSave; + INT32 gid; + + SCHEDULER_LOCK(intSave); + gid = (INT32)OsCurrUserGet()->gid; + SCHEDULER_UNLOCK(intSave); + + return gid; +#else + return 0; +#endif +} + +STATIC UINT32 OsProcessCreateInit(LosProcessCB *processCB, UINT32 flags, const CHAR *name, UINT16 priority) +{ + ProcessGroup *group = NULL; + UINT32 ret = OsInitPCB(processCB, flags, priority, name); + if (ret != LOS_OK) { + goto EXIT; + } + +#ifdef LOSCFG_KERNEL_LITEIPC + if (OsProcessIsUserMode(processCB)) { + ret = LiteIpcPoolInit(&(processCB->ipcInfo)); + if (ret != LOS_OK) { + ret = LOS_ENOMEM; + goto EXIT; + } + } +#endif + +#ifdef LOSCFG_FS_VFS + processCB->files = alloc_files(); + if (processCB->files == NULL) { + ret = LOS_ENOMEM; + goto EXIT; + } +#endif + + group = OsCreateProcessGroup(processCB->processID); + if (group == NULL) { + ret = LOS_ENOMEM; + goto EXIT; + } + +#ifdef LOSCFG_SECURITY_CAPABILITY + processCB->user = OsCreateUser(0, 0, 1); + if (processCB->user == NULL) { + ret = LOS_ENOMEM; + goto EXIT; + } +#endif + + return LOS_OK; + +EXIT: + OsDeInitPCB(processCB); + return ret; +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsSystemProcessCreate(VOID) +{ + UINT32 ret = OsProcessInit(); + if (ret != LOS_OK) { + return ret; + } + + LosProcessCB *kerInitProcess = OS_PCB_FROM_PID(g_kernelInitProcess); + ret = OsProcessCreateInit(kerInitProcess, OS_KERNEL_MODE, "KProcess", 0); + if (ret != LOS_OK) { + return ret; + } + + kerInitProcess->processStatus &= ~OS_PROCESS_STATUS_INIT; + g_processGroup = kerInitProcess->group; + LOS_ListInit(&g_processGroup->groupList); + OsCurrProcessSet(kerInitProcess); + + LosProcessCB *idleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess); + ret = OsInitPCB(idleProcess, OS_KERNEL_MODE, OS_TASK_PRIORITY_LOWEST, "KIdle"); + if (ret != LOS_OK) { + return ret; + } + idleProcess->parentProcessID = kerInitProcess->processID; + LOS_ListTailInsert(&kerInitProcess->childrenList, &idleProcess->siblingList); + idleProcess->group = kerInitProcess->group; + LOS_ListTailInsert(&kerInitProcess->group->processList, &idleProcess->subordinateGroupList); +#ifdef LOSCFG_SECURITY_CAPABILITY + idleProcess->user = kerInitProcess->user; +#endif +#ifdef LOSCFG_FS_VFS + idleProcess->files = kerInitProcess->files; +#endif + + ret = OsIdleTaskCreate(); + if (ret != LOS_OK) { + return ret; + } + idleProcess->threadGroupID = OsPercpuGet()->idleTaskID; + + return LOS_OK; +} + +STATIC INLINE INT32 OsProcessSchedlerParamCheck(INT32 which, INT32 pid, UINT16 prio, UINT16 policy) +{ + if (OS_PID_CHECK_INVALID(pid)) { + return LOS_EINVAL; + } + + if (which != LOS_PRIO_PROCESS) { + return LOS_EINVAL; + } + + if (prio > OS_PROCESS_PRIORITY_LOWEST) { + return LOS_EINVAL; + } + + if (policy != LOS_SCHED_RR) { + return LOS_EINVAL; + } + + return LOS_OK; +} + +#ifdef LOSCFG_SECURITY_CAPABILITY +STATIC BOOL OsProcessCapPermitCheck(const LosProcessCB *processCB, UINT16 prio) +{ + LosProcessCB *runProcess = OsCurrProcessGet(); + + /* always trust kernel process */ + if (!OsProcessIsUserMode(runProcess)) { + return TRUE; + } + + /* user mode process can reduce the priority of itself */ + if ((runProcess->processID == processCB->processID) && (prio > processCB->priority)) { + return TRUE; + } + + /* user mode process with privilege of CAP_SCHED_SETPRIORITY can change the priority */ + if (IsCapPermit(CAP_SCHED_SETPRIORITY)) { + return TRUE; + } + return FALSE; +} +#endif + +LITE_OS_SEC_TEXT INT32 OsSetProcessScheduler(INT32 which, INT32 pid, UINT16 prio, UINT16 policy) +{ + LosProcessCB *processCB = NULL; + BOOL needSched = FALSE; + UINT32 intSave; + INT32 ret; + + ret = OsProcessSchedlerParamCheck(which, pid, prio, policy); + if (ret != LOS_OK) { + return -ret; + } + + SCHEDULER_LOCK(intSave); + processCB = OS_PCB_FROM_PID(pid); + if (OsProcessIsInactive(processCB)) { + ret = LOS_ESRCH; + goto EXIT; + } + +#ifdef LOSCFG_SECURITY_CAPABILITY + if (!OsProcessCapPermitCheck(processCB, prio)) { + ret = LOS_EPERM; + goto EXIT; + } +#endif + + needSched = OsSchedModifyProcessSchedParam(processCB, policy, prio); + SCHEDULER_UNLOCK(intSave); + + LOS_MpSchedule(OS_MP_CPU_ALL); + if (needSched && OS_SCHEDULER_ACTIVE) { + LOS_Schedule(); + } + return LOS_OK; + +EXIT: + SCHEDULER_UNLOCK(intSave); + return -ret; +} + +LITE_OS_SEC_TEXT INT32 LOS_SetProcessScheduler(INT32 pid, UINT16 policy, UINT16 prio) +{ + return OsSetProcessScheduler(LOS_PRIO_PROCESS, pid, prio, policy); +} + +LITE_OS_SEC_TEXT INT32 LOS_GetProcessScheduler(INT32 pid) +{ + UINT32 intSave; + + if (OS_PID_CHECK_INVALID(pid)) { + return -LOS_EINVAL; + } + + SCHEDULER_LOCK(intSave); + LosProcessCB *processCB = OS_PCB_FROM_PID(pid); + if (OsProcessIsUnused(processCB)) { + SCHEDULER_UNLOCK(intSave); + return -LOS_ESRCH; + } + + SCHEDULER_UNLOCK(intSave); + + return LOS_SCHED_RR; +} + +LITE_OS_SEC_TEXT INT32 LOS_SetProcessPriority(INT32 pid, UINT16 prio) +{ + return OsSetProcessScheduler(LOS_PRIO_PROCESS, pid, prio, LOS_GetProcessScheduler(pid)); +} + +LITE_OS_SEC_TEXT INT32 OsGetProcessPriority(INT32 which, INT32 pid) +{ + LosProcessCB *processCB = NULL; + INT32 prio; + UINT32 intSave; + (VOID)which; + + if (OS_PID_CHECK_INVALID(pid)) { + return -LOS_EINVAL; + } + + if (which != LOS_PRIO_PROCESS) { + return -LOS_EINVAL; + } + + SCHEDULER_LOCK(intSave); + processCB = OS_PCB_FROM_PID(pid); + if (OsProcessIsUnused(processCB)) { + prio = -LOS_ESRCH; + goto OUT; + } + + prio = (INT32)processCB->priority; + +OUT: + SCHEDULER_UNLOCK(intSave); + return prio; +} + +LITE_OS_SEC_TEXT INT32 LOS_GetProcessPriority(INT32 pid) +{ + return OsGetProcessPriority(LOS_PRIO_PROCESS, pid); +} + +STATIC VOID OsWaitInsertWaitListInOrder(LosTaskCB *runTask, LosProcessCB *processCB) +{ + LOS_DL_LIST *head = &processCB->waitList; + LOS_DL_LIST *list = head; + LosTaskCB *taskCB = NULL; + + if (runTask->waitFlag == OS_PROCESS_WAIT_GID) { + while (list->pstNext != head) { + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(list)); + if (taskCB->waitFlag == OS_PROCESS_WAIT_PRO) { + list = list->pstNext; + continue; + } + break; + } + } else if (runTask->waitFlag == OS_PROCESS_WAIT_ANY) { + while (list->pstNext != head) { + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(list)); + if (taskCB->waitFlag != OS_PROCESS_WAIT_ANY) { + list = list->pstNext; + continue; + } + break; + } + } + /* if runTask->waitFlag == OS_PROCESS_WAIT_PRO, + * this node is inserted directly into the header of the waitList + */ + + (VOID)OsSchedTaskWait(list->pstNext, LOS_WAIT_FOREVER, TRUE); + return; +} + +STATIC UINT32 OsWaitSetFlag(const LosProcessCB *processCB, INT32 pid, LosProcessCB **child) +{ + LosProcessCB *childCB = NULL; + ProcessGroup *group = NULL; + LosTaskCB *runTask = OsCurrTaskGet(); + UINT32 ret; + + if (pid > 0) { + /* Wait for the child process whose process number is pid. */ + childCB = OsFindExitChildProcess(processCB, pid); + if (childCB != NULL) { + goto WAIT_BACK; + } + + ret = OsFindChildProcess(processCB, pid); + if (ret != LOS_OK) { + return LOS_ECHILD; + } + runTask->waitFlag = OS_PROCESS_WAIT_PRO; + runTask->waitID = pid; + } else if (pid == 0) { + /* Wait for any child process in the same process group */ + childCB = OsFindGroupExitProcess(processCB->group, OS_INVALID_VALUE); + if (childCB != NULL) { + goto WAIT_BACK; + } + runTask->waitID = processCB->group->groupID; + runTask->waitFlag = OS_PROCESS_WAIT_GID; + } else if (pid == -1) { + /* Wait for any child process */ + childCB = OsFindExitChildProcess(processCB, OS_INVALID_VALUE); + if (childCB != NULL) { + goto WAIT_BACK; + } + runTask->waitID = pid; + runTask->waitFlag = OS_PROCESS_WAIT_ANY; + } else { /* pid < -1 */ + /* Wait for any child process whose group number is the pid absolute value. */ + group = OsFindProcessGroup(-pid); + if (group == NULL) { + return LOS_ECHILD; + } + + childCB = OsFindGroupExitProcess(group, OS_INVALID_VALUE); + if (childCB != NULL) { + goto WAIT_BACK; + } + + runTask->waitID = -pid; + runTask->waitFlag = OS_PROCESS_WAIT_GID; + } + +WAIT_BACK: + *child = childCB; + return LOS_OK; +} + +STATIC UINT32 OsWaitRecycleChildProcess(const LosProcessCB *childCB, UINT32 intSave, INT32 *status, siginfo_t *info) +{ + ProcessGroup *group = NULL; + UINT32 pid = childCB->processID; + UINT16 mode = childCB->processMode; + INT32 exitCode = childCB->exitCode; + UINT32 uid = 0; + +#ifdef LOSCFG_SECURITY_CAPABILITY + if (childCB->user != NULL) { + uid = childCB->user->userID; + } +#endif + + OsRecycleZombiesProcess((LosProcessCB *)childCB, &group); + SCHEDULER_UNLOCK(intSave); + + if (status != NULL) { + if (mode == OS_USER_MODE) { + (VOID)LOS_ArchCopyToUser((VOID *)status, (const VOID *)(&(exitCode)), sizeof(INT32)); + } else { + *status = exitCode; + } + } + /* get signal info */ + if (info != NULL) { + siginfo_t tempinfo = { 0 }; + + tempinfo.si_signo = SIGCHLD; + tempinfo.si_errno = 0; + tempinfo.si_pid = pid; + tempinfo.si_uid = uid; + /* + * Process exit code + * 31 15 8 7 0 + * | | exit code | core dump | signal | + */ + if ((exitCode & 0x7f) == 0) { + tempinfo.si_code = CLD_EXITED; + tempinfo.si_status = (exitCode >> 8U); + } else { + tempinfo.si_code = (exitCode & 0x80) ? CLD_DUMPED : CLD_KILLED; + tempinfo.si_status = (exitCode & 0x7f); + } + + if (mode == OS_USER_MODE) { + (VOID)LOS_ArchCopyToUser((VOID *)(info), (const VOID *)(&(tempinfo)), sizeof(siginfo_t)); + } else { + (VOID)memcpy_s((VOID *)(info), sizeof(siginfo_t), (const VOID *)(&(tempinfo)), sizeof(siginfo_t)); + } + } + (VOID)LOS_MemFree(m_aucSysMem1, group); + return pid; +} + +STATIC UINT32 OsWaitChildProcessCheck(LosProcessCB *processCB, INT32 pid, LosProcessCB **childCB) +{ + if (LOS_ListEmpty(&(processCB->childrenList)) && LOS_ListEmpty(&(processCB->exitChildList))) { + return LOS_ECHILD; + } + + return OsWaitSetFlag(processCB, pid, childCB); +} + +STATIC UINT32 OsWaitOptionsCheck(UINT32 options) +{ + UINT32 flag = LOS_WAIT_WNOHANG | LOS_WAIT_WUNTRACED | LOS_WAIT_WCONTINUED; + + flag = ~flag & options; + if (flag != 0) { + return LOS_EINVAL; + } + + if ((options & (LOS_WAIT_WCONTINUED | LOS_WAIT_WUNTRACED)) != 0) { + return LOS_EOPNOTSUPP; + } + + if (OS_INT_ACTIVE) { + return LOS_EINTR; + } + + return LOS_OK; +} + +STATIC INT32 OsWait(INT32 pid, USER INT32 *status, USER siginfo_t *info, UINT32 options, VOID *rusage) +{ + (VOID)rusage; + UINT32 ret; + UINT32 intSave; + LosProcessCB *childCB = NULL; + LosProcessCB *processCB = NULL; + LosTaskCB *runTask = NULL; + + SCHEDULER_LOCK(intSave); + processCB = OsCurrProcessGet(); + runTask = OsCurrTaskGet(); + + ret = OsWaitChildProcessCheck(processCB, pid, &childCB); + if (ret != LOS_OK) { + pid = -ret; + goto ERROR; + } + + if (childCB != NULL) { + return (INT32)OsWaitRecycleChildProcess(childCB, intSave, status, info); + } + + if ((options & LOS_WAIT_WNOHANG) != 0) { + runTask->waitFlag = 0; + pid = 0; + goto ERROR; + } + + OsWaitInsertWaitListInOrder(runTask, processCB); + + runTask->waitFlag = 0; + if (runTask->waitID == OS_INVALID_VALUE) { + pid = -LOS_ECHILD; + goto ERROR; + } + + childCB = OS_PCB_FROM_PID(runTask->waitID); + if (!(childCB->processStatus & OS_PROCESS_STATUS_ZOMBIES)) { + pid = -LOS_ESRCH; + goto ERROR; + } + + return (INT32)OsWaitRecycleChildProcess(childCB, intSave, status, info); + +ERROR: + SCHEDULER_UNLOCK(intSave); + return pid; +} + +LITE_OS_SEC_TEXT INT32 LOS_Wait(INT32 pid, USER INT32 *status, UINT32 options, VOID *rusage) +{ + (VOID)rusage; + UINT32 ret; + + ret = OsWaitOptionsCheck(options); + if (ret != LOS_OK) { + return -ret; + } + + return OsWait(pid, status, NULL, options, NULL); +} + +STATIC UINT32 OsWaitidOptionsCheck(UINT32 options) +{ + UINT32 flag = LOS_WAIT_WNOHANG | LOS_WAIT_WSTOPPED | LOS_WAIT_WCONTINUED | LOS_WAIT_WEXITED | LOS_WAIT_WNOWAIT; + + flag = ~flag & options; + if ((flag != 0) || (options == 0)) { + return LOS_EINVAL; + } + + /* + * only support LOS_WAIT_WNOHANG | LOS_WAIT_WEXITED + * notsupport LOS_WAIT_WSTOPPED | LOS_WAIT_WCONTINUED | LOS_WAIT_WNOWAIT + */ + if ((options & (LOS_WAIT_WSTOPPED | LOS_WAIT_WCONTINUED | LOS_WAIT_WNOWAIT)) != 0) { + return LOS_EOPNOTSUPP; + } + + if (OS_INT_ACTIVE) { + return LOS_EINTR; + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT INT32 LOS_Waitid(INT32 pid, USER siginfo_t *info, UINT32 options, VOID *rusage) +{ + (VOID)rusage; + UINT32 ret; + + /* check options value */ + ret = OsWaitidOptionsCheck(options); + if (ret != LOS_OK) { + return -ret; + } + + return OsWait(pid, NULL, info, options, NULL); +} + +STATIC UINT32 OsSetProcessGroupCheck(const LosProcessCB *processCB, UINT32 gid) +{ + LosProcessCB *runProcessCB = OsCurrProcessGet(); + LosProcessCB *groupProcessCB = OS_PCB_FROM_PID(gid); + + if (OsProcessIsInactive(processCB)) { + return LOS_ESRCH; + } + + if (!OsProcessIsUserMode(processCB) || !OsProcessIsUserMode(groupProcessCB)) { + return LOS_EPERM; + } + + if (runProcessCB->processID == processCB->parentProcessID) { + if (processCB->processStatus & OS_PROCESS_FLAG_ALREADY_EXEC) { + return LOS_EACCES; + } + } else if (processCB->processID != runProcessCB->processID) { + return LOS_ESRCH; + } + + /* Add the process to another existing process group */ + if (processCB->processID != gid) { + if (!(groupProcessCB->processStatus & OS_PROCESS_FLAG_GROUP_LEADER)) { + return LOS_EPERM; + } + + if ((groupProcessCB->parentProcessID != processCB->parentProcessID) && (gid != processCB->parentProcessID)) { + return LOS_EPERM; + } + } + + return LOS_OK; +} + +STATIC UINT32 OsSetProcessGroupIDUnsafe(UINT32 pid, UINT32 gid, ProcessGroup **group) +{ + ProcessGroup *oldGroup = NULL; + ProcessGroup *newGroup = NULL; + LosProcessCB *processCB = OS_PCB_FROM_PID(pid); + UINT32 ret = OsSetProcessGroupCheck(processCB, gid); + if (ret != LOS_OK) { + return ret; + } + + if (processCB->group->groupID == gid) { + return LOS_OK; + } + + oldGroup = processCB->group; + OsExitProcessGroup(processCB, group); + + newGroup = OsFindProcessGroup(gid); + if (newGroup != NULL) { + LOS_ListTailInsert(&newGroup->processList, &processCB->subordinateGroupList); + processCB->group = newGroup; + return LOS_OK; + } + + newGroup = OsCreateProcessGroup(gid); + if (newGroup == NULL) { + LOS_ListTailInsert(&oldGroup->processList, &processCB->subordinateGroupList); + processCB->group = oldGroup; + if (*group != NULL) { + LOS_ListTailInsert(&g_processGroup->groupList, &oldGroup->groupList); + processCB = OS_PCB_FROM_PID(oldGroup->groupID); + processCB->processStatus |= OS_PROCESS_FLAG_GROUP_LEADER; + *group = NULL; + } + return LOS_EPERM; + } + return LOS_OK; +} + +LITE_OS_SEC_TEXT INT32 OsSetProcessGroupID(UINT32 pid, UINT32 gid) +{ + ProcessGroup *group = NULL; + UINT32 ret; + UINT32 intSave; + + if ((OS_PID_CHECK_INVALID(pid)) || (OS_PID_CHECK_INVALID(gid))) { + return -LOS_EINVAL; + } + + SCHEDULER_LOCK(intSave); + ret = OsSetProcessGroupIDUnsafe(pid, gid, &group); + SCHEDULER_UNLOCK(intSave); + (VOID)LOS_MemFree(m_aucSysMem1, group); + return -ret; +} + +LITE_OS_SEC_TEXT INT32 OsSetCurrProcessGroupID(UINT32 gid) +{ + return OsSetProcessGroupID(OsCurrProcessGet()->processID, gid); +} + +LITE_OS_SEC_TEXT INT32 LOS_GetProcessGroupID(UINT32 pid) +{ + INT32 gid; + UINT32 intSave; + LosProcessCB *processCB = NULL; + + if (OS_PID_CHECK_INVALID(pid)) { + return -LOS_EINVAL; + } + + SCHEDULER_LOCK(intSave); + processCB = OS_PCB_FROM_PID(pid); + if (OsProcessIsUnused(processCB)) { + gid = -LOS_ESRCH; + goto EXIT; + } + + gid = (INT32)processCB->group->groupID; + +EXIT: + SCHEDULER_UNLOCK(intSave); + return gid; +} + +LITE_OS_SEC_TEXT INT32 LOS_GetCurrProcessGroupID(VOID) +{ + return LOS_GetProcessGroupID(OsCurrProcessGet()->processID); +} + +#ifdef LOSCFG_KERNEL_VM +STATIC LosProcessCB *OsGetFreePCB(VOID) +{ + LosProcessCB *processCB = NULL; + UINT32 intSave; + + SCHEDULER_LOCK(intSave); + if (LOS_ListEmpty(&g_freeProcess)) { + SCHEDULER_UNLOCK(intSave); + PRINT_ERR("No idle PCB in the system!\n"); + return NULL; + } + + processCB = OS_PCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_freeProcess)); + LOS_ListDelete(&processCB->pendList); + SCHEDULER_UNLOCK(intSave); + + return processCB; +} + +STATIC VOID *OsUserInitStackAlloc(LosProcessCB *processCB, UINT32 *size) +{ + LosVmMapRegion *region = NULL; + UINT32 stackSize = ALIGN(OS_USER_TASK_STACK_SIZE, PAGE_SIZE); + + region = LOS_RegionAlloc(processCB->vmSpace, 0, stackSize, + VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | + VM_MAP_REGION_FLAG_PERM_WRITE, 0); + if (region == NULL) { + return NULL; + } + + LOS_SetRegionTypeAnon(region); + region->regionFlags |= VM_MAP_REGION_FLAG_STACK; + + *size = stackSize; + + return (VOID *)(UINTPTR)region->range.base; +} + +LITE_OS_SEC_TEXT UINT32 OsExecRecycleAndInit(LosProcessCB *processCB, const CHAR *name, + LosVmSpace *oldSpace, UINTPTR oldFiles) +{ + UINT32 ret; + const CHAR *processName = NULL; + + if ((processCB == NULL) || (name == NULL)) { + return LOS_NOK; + } + + processName = strrchr(name, '/'); + processName = (processName == NULL) ? name : (processName + 1); /* 1: Do not include '/' */ + + ret = (UINT32)OsSetTaskName(OsCurrTaskGet(), processName, TRUE); + if (ret != LOS_OK) { + return ret; + } + +#ifdef LOSCFG_KERNEL_LITEIPC + ret = LiteIpcPoolInit(&(processCB->ipcInfo)); + if (ret != LOS_OK) { + return LOS_NOK; + } +#endif + + processCB->sigHandler = 0; + OsCurrTaskGet()->sig.sigprocmask = 0; + + LOS_VmSpaceFree(oldSpace); +#ifdef LOSCFG_FS_VFS + CloseOnExec((struct files_struct *)oldFiles); + delete_files_snapshot((struct files_struct *)oldFiles); +#endif + + OsSwtmrRecycle(processCB->processID); + processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID; + +#ifdef LOSCFG_SECURITY_VID + VidMapDestroy(processCB); + ret = VidMapListInit(processCB); + if (ret != LOS_OK) { + return LOS_NOK; + } +#endif + + processCB->processStatus &= ~OS_PROCESS_FLAG_EXIT; + processCB->processStatus |= OS_PROCESS_FLAG_ALREADY_EXEC; + + return LOS_OK; +} + +LITE_OS_SEC_TEXT UINT32 OsExecStart(const TSK_ENTRY_FUNC entry, UINTPTR sp, UINTPTR mapBase, UINT32 mapSize) +{ + UINT32 intSave; + + if (entry == NULL) { + return LOS_NOK; + } + + if ((sp == 0) || (LOS_Align(sp, LOSCFG_STACK_POINT_ALIGN_SIZE) != sp)) { + return LOS_NOK; + } + + if ((mapBase == 0) || (mapSize == 0) || (sp <= mapBase) || (sp > (mapBase + mapSize))) { + return LOS_NOK; + } + + LosTaskCB *taskCB = OsCurrTaskGet(); + + SCHEDULER_LOCK(intSave); + taskCB->userMapBase = mapBase; + taskCB->userMapSize = mapSize; + taskCB->taskEntry = (TSK_ENTRY_FUNC)entry; + + TaskContext *taskContext = (TaskContext *)OsTaskStackInit(taskCB->taskID, taskCB->stackSize, + (VOID *)taskCB->topOfStack, FALSE); + OsUserTaskStackInit(taskContext, (UINTPTR)taskCB->taskEntry, sp); + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +STATIC UINT32 OsUserInitProcessStart(UINT32 processID, TSK_INIT_PARAM_S *param) +{ + UINT32 intSave; + UINT32 taskID; + INT32 ret; + + taskID = OsCreateUserTask(processID, param); + if (taskID == OS_INVALID_VALUE) { + return LOS_NOK; + } + + ret = LOS_SetTaskScheduler(taskID, LOS_SCHED_RR, OS_TASK_PRIORITY_LOWEST); + if (ret != LOS_OK) { + PRINT_ERR("User init process set scheduler failed! ERROR:%d \n", ret); + SCHEDULER_LOCK(intSave); + (VOID)OsTaskDeleteUnsafe(OS_TCB_FROM_TID(taskID), OS_PRO_EXIT_OK, intSave); + return LOS_NOK; + } + + return LOS_OK; +} + +STATIC UINT32 OsLoadUserInit(LosProcessCB *processCB) +{ + /* userInitTextStart ----- + * | user text | + * + * | user data | initSize + * userInitBssStart --- + * | user bss | initBssSize + * userInitEnd --- ----- + */ + errno_t errRet; + INT32 ret; + CHAR *userInitTextStart = (CHAR *)&__user_init_entry; + CHAR *userInitBssStart = (CHAR *)&__user_init_bss; + CHAR *userInitEnd = (CHAR *)&__user_init_end; + UINT32 initBssSize = userInitEnd - userInitBssStart; + UINT32 initSize = userInitEnd - userInitTextStart; + VOID *userBss = NULL; + VOID *userText = NULL; + + if ((LOS_Align((UINTPTR)userInitTextStart, PAGE_SIZE) != (UINTPTR)userInitTextStart) || + (LOS_Align((UINTPTR)userInitEnd, PAGE_SIZE) != (UINTPTR)userInitEnd)) { + return LOS_EINVAL; + } + + if ((initSize == 0) || (initSize <= initBssSize)) { + return LOS_EINVAL; + } + + userText = LOS_PhysPagesAllocContiguous(initSize >> PAGE_SHIFT); + if (userText == NULL) { + return LOS_NOK; + } + + errRet = memcpy_s(userText, initSize, (VOID *)&__user_init_load_addr, initSize - initBssSize); + if (errRet != EOK) { + PRINT_ERR("Load user init text, data and bss failed! err : %d\n", errRet); + goto ERROR; + } + ret = LOS_VaddrToPaddrMmap(processCB->vmSpace, (VADDR_T)(UINTPTR)userInitTextStart, LOS_PaddrQuery(userText), + initSize, VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE | + VM_MAP_REGION_FLAG_FIXED | VM_MAP_REGION_FLAG_PERM_EXECUTE | + VM_MAP_REGION_FLAG_PERM_USER); + if (ret < 0) { + PRINT_ERR("Mmap user init text, data and bss failed! err : %d\n", ret); + goto ERROR; + } + + /* The User init boot segment may not actually exist */ + if (initBssSize != 0) { + userBss = (VOID *)((UINTPTR)userText + userInitBssStart - userInitTextStart); + errRet = memset_s(userBss, initBssSize, 0, initBssSize); + if (errRet != EOK) { + PRINT_ERR("memset user init bss failed! err : %d\n", errRet); + goto ERROR; + } + } + + return LOS_OK; + +ERROR: + (VOID)LOS_PhysPagesFreeContiguous(userText, initSize >> PAGE_SHIFT); + return LOS_NOK; +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID) +{ + UINT32 ret; + UINT32 size; + TSK_INIT_PARAM_S param = { 0 }; + VOID *stack = NULL; + + LosProcessCB *processCB = OS_PCB_FROM_PID(g_userInitProcess); + ret = OsProcessCreateInit(processCB, OS_USER_MODE, "Init", OS_PROCESS_USERINIT_PRIORITY); + if (ret != LOS_OK) { + return ret; + } + + ret = OsLoadUserInit(processCB); + if (ret != LOS_OK) { + goto ERROR; + } + + stack = OsUserInitStackAlloc(processCB, &size); + if (stack == NULL) { + PRINT_ERR("Alloc user init process user stack failed!\n"); + goto ERROR; + } + + param.pfnTaskEntry = (TSK_ENTRY_FUNC)(CHAR *)&__user_init_entry; + param.userParam.userSP = (UINTPTR)stack + size; + param.userParam.userMapBase = (UINTPTR)stack; + param.userParam.userMapSize = size; + param.uwResved = OS_TASK_FLAG_PTHREAD_JOIN; + ret = OsUserInitProcessStart(g_userInitProcess, ¶m); + if (ret != LOS_OK) { + (VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize); + goto ERROR; + } + + return LOS_OK; + +ERROR: + OsDeInitPCB(processCB); + return ret; +} + +STATIC UINT32 OsCopyUser(LosProcessCB *childCB, LosProcessCB *parentCB) +{ +#ifdef LOSCFG_SECURITY_CAPABILITY + UINT32 size = sizeof(User) + sizeof(UINT32) * (parentCB->user->groupNumber - 1); + childCB->user = LOS_MemAlloc(m_aucSysMem1, size); + if (childCB->user == NULL) { + return LOS_ENOMEM; + } + + (VOID)memcpy_s(childCB->user, size, parentCB->user, size); +#endif + return LOS_OK; +} + +STATIC VOID OsInitCopyTaskParam(LosProcessCB *childProcessCB, const CHAR *name, UINTPTR entry, UINT32 size, + TSK_INIT_PARAM_S *childPara) +{ + LosTaskCB *mainThread = NULL; + UINT32 intSave; + + SCHEDULER_LOCK(intSave); + mainThread = OsCurrTaskGet(); + + if (OsProcessIsUserMode(childProcessCB)) { + childPara->pfnTaskEntry = mainThread->taskEntry; + childPara->uwStackSize = mainThread->stackSize; + childPara->userParam.userArea = mainThread->userArea; + childPara->userParam.userMapBase = mainThread->userMapBase; + childPara->userParam.userMapSize = mainThread->userMapSize; + } else { + childPara->pfnTaskEntry = (TSK_ENTRY_FUNC)entry; + childPara->uwStackSize = size; + } + childPara->pcName = (CHAR *)name; + childPara->policy = mainThread->policy; + childPara->usTaskPrio = mainThread->priority; + childPara->processID = childProcessCB->processID; + if (mainThread->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) { + childPara->uwResved = OS_TASK_FLAG_PTHREAD_JOIN; + } else if (mainThread->taskStatus & OS_TASK_FLAG_DETACHED) { + childPara->uwResved = OS_TASK_FLAG_DETACHED; + } + + SCHEDULER_UNLOCK(intSave); +} + +STATIC UINT32 OsCopyTask(UINT32 flags, LosProcessCB *childProcessCB, const CHAR *name, UINTPTR entry, UINT32 size) +{ + LosTaskCB *runTask = OsCurrTaskGet(); + TSK_INIT_PARAM_S childPara = { 0 }; + UINT32 ret; + UINT32 intSave; + UINT32 taskID; + + OsInitCopyTaskParam(childProcessCB, name, entry, size, &childPara); + + ret = LOS_TaskCreateOnly(&taskID, &childPara); + if (ret != LOS_OK) { + if (ret == LOS_ERRNO_TSK_TCB_UNAVAILABLE) { + return LOS_EAGAIN; + } + return LOS_ENOMEM; + } + + LosTaskCB *childTaskCB = OS_TCB_FROM_TID(taskID); + childTaskCB->taskStatus = runTask->taskStatus; + if (childTaskCB->taskStatus & OS_TASK_STATUS_RUNNING) { + childTaskCB->taskStatus &= ~OS_TASK_STATUS_RUNNING; + } else { + if (OS_SCHEDULER_ACTIVE) { + LOS_Panic("Clone thread status not running error status: 0x%x\n", childTaskCB->taskStatus); + } + childTaskCB->taskStatus &= ~OS_TASK_STATUS_UNUSED; + childProcessCB->priority = OS_PROCESS_PRIORITY_LOWEST; + } + + if (OsProcessIsUserMode(childProcessCB)) { + SCHEDULER_LOCK(intSave); + OsUserCloneParentStack(childTaskCB->stackPointer, runTask->topOfStack, runTask->stackSize); + SCHEDULER_UNLOCK(intSave); + } + return LOS_OK; +} + +STATIC UINT32 OsCopyParent(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB) +{ + UINT32 ret; + UINT32 intSave; + LosProcessCB *parentProcessCB = NULL; + + SCHEDULER_LOCK(intSave); + childProcessCB->priority = runProcessCB->priority; + + if (flags & CLONE_PARENT) { + parentProcessCB = OS_PCB_FROM_PID(runProcessCB->parentProcessID); + } else { + parentProcessCB = runProcessCB; + } + childProcessCB->parentProcessID = parentProcessCB->processID; + LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList); + childProcessCB->group = parentProcessCB->group; + LOS_ListTailInsert(&parentProcessCB->group->processList, &childProcessCB->subordinateGroupList); + ret = OsCopyUser(childProcessCB, parentProcessCB); + + SCHEDULER_UNLOCK(intSave); + return ret; +} + +STATIC UINT32 OsCopyMM(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB) +{ + status_t status; + UINT32 intSave; + + if (!OsProcessIsUserMode(childProcessCB)) { + return LOS_OK; + } + + if (flags & CLONE_VM) { + SCHEDULER_LOCK(intSave); + childProcessCB->vmSpace->archMmu.virtTtb = runProcessCB->vmSpace->archMmu.virtTtb; + childProcessCB->vmSpace->archMmu.physTtb = runProcessCB->vmSpace->archMmu.physTtb; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; + } + + status = LOS_VmSpaceClone(runProcessCB->vmSpace, childProcessCB->vmSpace); + if (status != LOS_OK) { + return LOS_ENOMEM; + } + return LOS_OK; +} + +STATIC UINT32 OsCopyFile(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB) +{ +#ifdef LOSCFG_FS_VFS + if (flags & CLONE_FILES) { + childProcessCB->files = runProcessCB->files; + } else { + childProcessCB->files = dup_fd(runProcessCB->files); + } + if (childProcessCB->files == NULL) { + return LOS_ENOMEM; + } +#endif + + childProcessCB->consoleID = runProcessCB->consoleID; + childProcessCB->umask = runProcessCB->umask; + return LOS_OK; +} + +STATIC UINT32 OsForkInitPCB(UINT32 flags, LosProcessCB *child, const CHAR *name, UINTPTR sp, UINT32 size) +{ + UINT32 ret; + LosProcessCB *run = OsCurrProcessGet(); + + ret = OsInitPCB(child, run->processMode, OS_PROCESS_PRIORITY_LOWEST, name); + if (ret != LOS_OK) { + return ret; + } + + ret = OsCopyParent(flags, child, run); + if (ret != LOS_OK) { + return ret; + } + + return OsCopyTask(flags, child, name, sp, size); +} + +STATIC UINT32 OsChildSetProcessGroupAndSched(LosProcessCB *child, LosProcessCB *run) +{ + UINT32 intSave; + UINT32 ret; + ProcessGroup *group = NULL; + + SCHEDULER_LOCK(intSave); + if (run->group->groupID == OS_USER_PRIVILEGE_PROCESS_GROUP) { + ret = OsSetProcessGroupIDUnsafe(child->processID, child->processID, &group); + if (ret != LOS_OK) { + SCHEDULER_UNLOCK(intSave); + return LOS_ENOMEM; + } + } + + OsSchedTaskEnQueue(OS_TCB_FROM_TID(child->threadGroupID)); + SCHEDULER_UNLOCK(intSave); + + (VOID)LOS_MemFree(m_aucSysMem1, group); + return LOS_OK; +} + +STATIC UINT32 OsCopyProcessResources(UINT32 flags, LosProcessCB *child, LosProcessCB *run) +{ + UINT32 ret; + + ret = OsCopyMM(flags, child, run); + if (ret != LOS_OK) { + return ret; + } + + ret = OsCopyFile(flags, child, run); + if (ret != LOS_OK) { + return ret; + } + +#ifdef LOSCFG_KERNEL_LITEIPC + if (OsProcessIsUserMode(child)) { + ret = LiteIpcPoolReInit(&child->ipcInfo, (const ProcIpcInfo *)(&run->ipcInfo)); + if (ret != LOS_OK) { + return LOS_ENOMEM; + } + } +#endif + +#ifdef LOSCFG_SECURITY_CAPABILITY + OsCopyCapability(run, child); +#endif + + return LOS_OK; +} + +STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 size) +{ + UINT32 intSave, ret, processID; + LosProcessCB *run = OsCurrProcessGet(); + + LosProcessCB *child = OsGetFreePCB(); + if (child == NULL) { + return -LOS_EAGAIN; + } + processID = child->processID; + + ret = OsForkInitPCB(flags, child, name, sp, size); + if (ret != LOS_OK) { + goto ERROR_INIT; + } + + ret = OsCopyProcessResources(flags, child, run); + if (ret != LOS_OK) { + goto ERROR_TASK; + } + + ret = OsChildSetProcessGroupAndSched(child, run); + if (ret != LOS_OK) { + goto ERROR_TASK; + } + + LOS_MpSchedule(OS_MP_CPU_ALL); + if (OS_SCHEDULER_ACTIVE) { + LOS_Schedule(); + } + + return processID; + +ERROR_TASK: + SCHEDULER_LOCK(intSave); + (VOID)OsTaskDeleteUnsafe(OS_TCB_FROM_TID(child->threadGroupID), OS_PRO_EXIT_OK, intSave); +ERROR_INIT: + OsDeInitPCB(child); + return -ret; +} + +LITE_OS_SEC_TEXT INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size) +{ + UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | CLONE_VFORK | CLONE_VM; + + if (flags & (~cloneFlag)) { + PRINT_WARN("Clone dont support some flags!\n"); + } + + return OsCopyProcess(cloneFlag & flags, NULL, sp, size); +} + +LITE_OS_SEC_TEXT INT32 LOS_Fork(UINT32 flags, const CHAR *name, const TSK_ENTRY_FUNC entry, UINT32 stackSize) +{ + UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | CLONE_VFORK | CLONE_FILES; + + if (flags & (~cloneFlag)) { + PRINT_WARN("Clone dont support some flags!\n"); + } + + flags |= CLONE_FILES; + return OsCopyProcess(cloneFlag & flags, name, (UINTPTR)entry, stackSize); +} +#else +LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID) +{ + return 0; +} +#endif + +LITE_OS_SEC_TEXT VOID LOS_Exit(INT32 status) +{ + UINT32 intSave; + + /* The exit of a kernel - state process must be kernel - state and all threads must actively exit */ + LosProcessCB *processCB = OsCurrProcessGet(); + SCHEDULER_LOCK(intSave); + if (!OsProcessIsUserMode(processCB) && (processCB->threadNumber != 1)) { + SCHEDULER_UNLOCK(intSave); + PRINT_ERR("Kernel-state processes with multiple threads are not allowed to exit directly\n"); + return; + } + SCHEDULER_UNLOCK(intSave); + + OsTaskExitGroup((UINT32)status); + OsProcessExit(OsCurrTaskGet(), (UINT32)status); +} + +LITE_OS_SEC_TEXT INT32 LOS_GetUsedPIDList(UINT32 *pidList, INT32 pidMaxNum) +{ + LosProcessCB *pcb = NULL; + INT32 num = 0; + UINT32 intSave; + UINT32 pid = 1; + + if (pidList == NULL) { + return 0; + } + SCHEDULER_LOCK(intSave); + while (OsProcessIDUserCheckInvalid(pid) == false) { + pcb = OS_PCB_FROM_PID(pid); + pid++; + if (OsProcessIsUnused(pcb)) { + continue; + } + pidList[num] = pcb->processID; + num++; + if (num >= pidMaxNum) { + break; + } + } + SCHEDULER_UNLOCK(intSave); + return num; +} + +#ifdef LOSCFG_FS_VFS +LITE_OS_SEC_TEXT struct fd_table_s *LOS_GetFdTable(UINT32 pid) +{ + LosProcessCB *pcb = NULL; + struct files_struct *files = NULL; + + if (OS_PID_CHECK_INVALID(pid)) { + return NULL; + } + pcb = OS_PCB_FROM_PID(pid); + files = pcb->files; + if (files == NULL) { + return NULL; + } + + return files->fdt; +} +#endif + +LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID) +{ + return OsCurrProcessGet()->processID; +} + +LITE_OS_SEC_TEXT VOID OsProcessExit(LosTaskCB *runTask, INT32 status) +{ + UINT32 intSave; + LOS_ASSERT(runTask == OsCurrTaskGet()); + + OsTaskResourcesToFree(runTask); + OsProcessResourcesToFree(OsCurrProcessGet()); + + SCHEDULER_LOCK(intSave); + OsProcessNaturalExit(runTask, status); + SCHEDULER_UNLOCK(intSave); +} + +LITE_OS_SEC_TEXT UINT32 LOS_GetSystemProcessMaximum(VOID) +{ + return g_processMaxNum; +} + +LITE_OS_SEC_TEXT UINT32 OsGetUserInitProcessID(VOID) +{ + return g_userInitProcess; +} + +LITE_OS_SEC_TEXT UINT32 OsGetKernelInitProcessID(VOID) +{ + return g_kernelInitProcess; +} + +LITE_OS_SEC_TEXT UINT32 OsGetIdleProcessID(VOID) +{ + return g_kernelIdleProcess; +} + +LITE_OS_SEC_TEXT VOID OsSetSigHandler(UINTPTR addr) +{ + OsCurrProcessGet()->sigHandler = addr; +} + +LITE_OS_SEC_TEXT UINTPTR OsGetSigHandler(VOID) +{ + return OsCurrProcessGet()->sigHandler; +} + diff --git a/core/los_smp.c b/core/los_smp.c new file mode 100644 index 0000000..1500227 --- /dev/null +++ b/core/los_smp.c @@ -0,0 +1,84 @@ +/* + * 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_smp.h" +#include "arch_config.h" +#include "los_atomic.h" +#include "los_task_pri.h" +#include "los_init_pri.h" +#include "los_process_pri.h" +#include "los_sched_pri.h" +#include "los_swtmr_pri.h" + +#ifdef LOSCFG_KERNEL_SMP +STATIC struct SmpOps *g_smpOps = NULL; + +STATIC VOID OsSmpSecondaryInit(VOID *arg) +{ + UNUSED(arg); + OsInitCall(LOS_INIT_LEVEL_PLATFORM); + + OsCurrProcessSet(OS_PCB_FROM_PID(OsGetKernelInitProcessID())); + OsInitCall(LOS_INIT_LEVEL_KMOD_BASIC); + +#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE + OsSwtmrInit(); +#endif + + OsInitCall(LOS_INIT_LEVEL_KMOD_EXTENDED); + + OsIdleTaskCreate(); + OsInitCall(LOS_INIT_LEVEL_KMOD_TASK); + + OsSchedStart(); +} + +VOID LOS_SmpOpsSet(struct SmpOps *ops) +{ + g_smpOps = ops; +} + +VOID OsSmpInit(VOID) +{ + UINT32 cpuNum = 1; /* Start the secondary cpus. */ + + if (g_smpOps == NULL) { + PRINT_ERR("Must call the interface(LOS_SmpOpsSet) to register smp operations firstly!\n"); + return; + } + + for (; cpuNum < CORE_NUM; cpuNum++) { + HalArchCpuOn(cpuNum, OsSmpSecondaryInit, g_smpOps, 0); + } + + return; +} +#endif diff --git a/core/los_swtmr.c b/core/los_swtmr.c new file mode 100644 index 0000000..dde50c6 --- /dev/null +++ b/core/los_swtmr.c @@ -0,0 +1,536 @@ +/* + * 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_swtmr_pri.h" +#include "los_init.h" +#include "los_process_pri.h" +#include "los_queue_pri.h" +#include "los_sched_pri.h" +#include "los_sortlink_pri.h" +#include "los_task_pri.h" +#include "los_hook.h" + +#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE +#if (LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0) +#error "swtmr maxnum cannot be zero" +#endif /* LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0 */ + +LITE_OS_SEC_BSS SWTMR_CTRL_S *g_swtmrCBArray = NULL; /* First address in Timer memory space */ +LITE_OS_SEC_BSS UINT8 *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler */ +LITE_OS_SEC_BSS LOS_DL_LIST g_swtmrFreeList; /* Free list of Software Timer */ + +/* spinlock for swtmr module, only available on SMP mode */ +LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin); +#define SWTMR_LOCK(state) LOS_SpinLockSave(&g_swtmrSpin, &(state)) +#define SWTMR_UNLOCK(state) LOS_SpinUnlockRestore(&g_swtmrSpin, (state)) + +LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID) +{ + SwtmrHandlerItemPtr swtmrHandlePtr = NULL; + SwtmrHandlerItem swtmrHandle; + UINT32 ret, swtmrHandlerQueue; + + swtmrHandlerQueue = OsPercpuGet()->swtmrHandlerQueue; + for (;;) { + ret = LOS_QueueRead(swtmrHandlerQueue, &swtmrHandlePtr, sizeof(CHAR *), LOS_WAIT_FOREVER); + if ((ret == LOS_OK) && (swtmrHandlePtr != NULL)) { + swtmrHandle.handler = swtmrHandlePtr->handler; + swtmrHandle.arg = swtmrHandlePtr->arg; + (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr); + if (swtmrHandle.handler != NULL) { + swtmrHandle.handler(swtmrHandle.arg); + } + } + } +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrTaskCreate(VOID) +{ + UINT32 ret, swtmrTaskID; + TSK_INIT_PARAM_S swtmrTask; + UINT32 cpuid = ArchCurrCpuid(); + + (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); + swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)OsSwtmrTask; + swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; + swtmrTask.pcName = "Swt_Task"; + swtmrTask.usTaskPrio = 0; + swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED; +#ifdef LOSCFG_KERNEL_SMP + swtmrTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(cpuid); +#endif + ret = LOS_TaskCreate(&swtmrTaskID, &swtmrTask); + if (ret == LOS_OK) { + g_percpu[cpuid].swtmrTaskID = swtmrTaskID; + OS_TCB_FROM_TID(swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK; + } + + return ret; +} + +LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINT32 processID) +{ + for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) { + if (g_swtmrCBArray[index].uwOwnerPid == processID) { + LOS_SwtmrDelete(index); + } + } +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID) +{ + UINT32 size; + UINT16 index; + UINT32 ret; + SWTMR_CTRL_S *swtmr = NULL; + UINT32 swtmrHandlePoolSize; + UINT32 cpuid = ArchCurrCpuid(); + if (cpuid == 0) { + size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT; + swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); /* system resident resource */ + if (swtmr == NULL) { + ret = LOS_ERRNO_SWTMR_NO_MEMORY; + goto ERROR; + } + + (VOID)memset_s(swtmr, size, 0, size); + g_swtmrCBArray = swtmr; + LOS_ListInit(&g_swtmrFreeList); + for (index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) { + swtmr->usTimerID = index; + LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode); + } + + swtmrHandlePoolSize = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE); + + g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, swtmrHandlePoolSize); /* system resident resource */ + if (g_swtmrHandlerPool == NULL) { + ret = LOS_ERRNO_SWTMR_NO_MEMORY; + goto ERROR; + } + + ret = LOS_MemboxInit(g_swtmrHandlerPool, swtmrHandlePoolSize, sizeof(SwtmrHandlerItem)); + if (ret != LOS_OK) { + ret = LOS_ERRNO_SWTMR_HANDLER_POOL_NO_MEM; + goto ERROR; + } + + ret = OsSchedSwtmrScanRegister((SchedScan)OsSwtmrScan); + if (ret != LOS_OK) { + goto ERROR; + } + } + + ret = LOS_QueueCreate(NULL, OS_SWTMR_HANDLE_QUEUE_SIZE, &g_percpu[cpuid].swtmrHandlerQueue, 0, sizeof(CHAR *)); + if (ret != LOS_OK) { + ret = LOS_ERRNO_SWTMR_QUEUE_CREATE_FAILED; + goto ERROR; + } + + ret = OsSwtmrTaskCreate(); + if (ret != LOS_OK) { + ret = LOS_ERRNO_SWTMR_TASK_CREATE_FAILED; + goto ERROR; + } + + ret = OsSortLinkInit(&g_percpu[cpuid].swtmrSortLink); + if (ret != LOS_OK) { + ret = LOS_ERRNO_SWTMR_SORTLINK_CREATE_FAILED; + goto ERROR; + } + + return LOS_OK; + +ERROR: + PRINT_ERR("OsSwtmrInit error! ret = %u\n", ret); + return ret; +} + +/* + * Description: Start Software Timer + * Input : swtmr --- Need to start software timer + */ +LITE_OS_SEC_TEXT VOID OsSwtmrStart(UINT64 currTime, SWTMR_CTRL_S *swtmr) +{ + UINT32 ticks; + + if ((swtmr->uwOverrun == 0) && ((swtmr->ucMode == LOS_SWTMR_MODE_ONCE) || + (swtmr->ucMode == LOS_SWTMR_MODE_OPP) || + (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE))) { + ticks = swtmr->uwExpiry; + } else { + ticks = swtmr->uwInterval; + } + swtmr->ucState = OS_SWTMR_STATUS_TICKING; + + OsAdd2SortLink(&swtmr->stSortList, swtmr->startTime, ticks, OS_SORT_LINK_SWTMR); + OsSchedUpdateExpireTime(currTime); + return; +} + +/* + * Description: Delete Software Timer + * Input : swtmr --- Need to delete software timer, When using, Ensure that it can't be NULL. + */ +STATIC INLINE VOID OsSwtmrDelete(SWTMR_CTRL_S *swtmr) +{ + /* insert to free list */ + LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode); + swtmr->ucState = OS_SWTMR_STATUS_UNUSED; + swtmr->uwOwnerPid = 0; +} + +STATIC INLINE VOID OsWakePendTimeSwtmr(Percpu *cpu, UINT64 currTime, SWTMR_CTRL_S *swtmr) +{ + LOS_SpinLock(&g_swtmrSpin); + SwtmrHandlerItemPtr swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool); + if (swtmrHandler != NULL) { + swtmrHandler->handler = swtmr->pfnHandler; + swtmrHandler->arg = swtmr->uwArg; + + if (LOS_QueueWrite(cpu->swtmrHandlerQueue, swtmrHandler, sizeof(CHAR *), LOS_NO_WAIT)) { + (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandler); + } + } + + if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) { + OsSwtmrDelete(swtmr); + + if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) { + swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT; + } else { + swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT; + } + } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) { + swtmr->ucState = OS_SWTMR_STATUS_CREATED; + } else { + swtmr->uwOverrun++; + OsSwtmrStart(currTime, swtmr); + } + + LOS_SpinUnlock(&g_swtmrSpin); +} + +/* + * Description: Tick interrupt interface module of software timer + * Return : LOS_OK on success or error code on failure + */ +LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID) +{ + Percpu *cpu = OsPercpuGet(); + SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink; + LOS_DL_LIST *listObject = &swtmrSortLink->sortLink; + + /* + * it needs to be carefully coped with, since the swtmr is in specific sortlink + * while other cores still has the chance to process it, like stop the timer. + */ + LOS_SpinLock(&cpu->swtmrSortLinkSpin); + + if (LOS_ListEmpty(listObject)) { + LOS_SpinUnlock(&cpu->swtmrSortLinkSpin); + return; + } + SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); + + UINT64 currTime = OsGetCurrSchedTimeCycle(); + while (sortList->responseTime <= currTime) { + sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); + SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList); + swtmr->startTime = GET_SORTLIST_VALUE(sortList); + OsDeleteNodeSortLink(swtmrSortLink, sortList); + LOS_SpinUnlock(&cpu->swtmrSortLinkSpin); + + OsHookCall(LOS_HOOK_TYPE_SWTMR_EXPIRED, swtmr); + OsWakePendTimeSwtmr(cpu, currTime, swtmr); + + LOS_SpinLock(&cpu->swtmrSortLinkSpin); + if (LOS_ListEmpty(listObject)) { + break; + } + + sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); + } + + LOS_SpinUnlock(&cpu->swtmrSortLinkSpin); +} + +/* + * Description: Get next timeout + * Return : Count of the Timer list + */ +LITE_OS_SEC_TEXT UINT32 OsSwtmrGetNextTimeout(VOID) +{ + return OsSortLinkGetNextExpireTime(&OsPercpuGet()->swtmrSortLink); +} + +/* + * Description: Stop of Software Timer interface + * Input : swtmr --- the software timer contrl handler + */ +LITE_OS_SEC_TEXT STATIC VOID OsSwtmrStop(SWTMR_CTRL_S *swtmr) +{ + OsDeleteSortLink(&swtmr->stSortList, OS_SORT_LINK_SWTMR); + + swtmr->ucState = OS_SWTMR_STATUS_CREATED; + swtmr->uwOverrun = 0; + + OsSchedUpdateExpireTime(OsGetCurrSchedTimeCycle()); +} + +/* + * Description: Get next software timer expiretime + * Input : swtmr --- the software timer contrl handler + */ +LITE_OS_SEC_TEXT STATIC UINT32 OsSwtmrTimeGet(const SWTMR_CTRL_S *swtmr) +{ + return OsSortLinkGetTargetExpireTime(&swtmr->stSortList); +} + +LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, + UINT8 mode, + SWTMR_PROC_FUNC handler, + UINT16 *swtmrID, + UINTPTR arg) +{ + SWTMR_CTRL_S *swtmr = NULL; + UINT32 intSave; + SortLinkList *sortList = NULL; + + if (interval == 0) { + return LOS_ERRNO_SWTMR_INTERVAL_NOT_SUITED; + } + + if ((mode != LOS_SWTMR_MODE_ONCE) && (mode != LOS_SWTMR_MODE_PERIOD) && + (mode != LOS_SWTMR_MODE_NO_SELFDELETE)) { + return LOS_ERRNO_SWTMR_MODE_INVALID; + } + + if (handler == NULL) { + return LOS_ERRNO_SWTMR_PTR_NULL; + } + + if (swtmrID == NULL) { + return LOS_ERRNO_SWTMR_RET_PTR_NULL; + } + + SWTMR_LOCK(intSave); + if (LOS_ListEmpty(&g_swtmrFreeList)) { + SWTMR_UNLOCK(intSave); + return LOS_ERRNO_SWTMR_MAXSIZE; + } + + sortList = LOS_DL_LIST_ENTRY(g_swtmrFreeList.pstNext, SortLinkList, sortLinkNode); + swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList); + LOS_ListDelete(LOS_DL_LIST_FIRST(&g_swtmrFreeList)); + SWTMR_UNLOCK(intSave); + + swtmr->uwOwnerPid = OsCurrProcessGet()->processID; + swtmr->pfnHandler = handler; + swtmr->ucMode = mode; + swtmr->uwOverrun = 0; + swtmr->uwInterval = interval; + swtmr->uwExpiry = interval; + swtmr->uwArg = arg; + swtmr->ucState = OS_SWTMR_STATUS_CREATED; + SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME); + *swtmrID = swtmr->usTimerID; + OsHookCall(LOS_HOOK_TYPE_SWTMR_CREATE, swtmr); + return LOS_OK; +} + +LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID) +{ + SWTMR_CTRL_S *swtmr = NULL; + UINT32 intSave; + UINT32 ret = LOS_OK; + UINT16 swtmrCBID; + + if (swtmrID >= OS_SWTMR_MAX_TIMERID) { + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT; + swtmr = g_swtmrCBArray + swtmrCBID; + + SWTMR_LOCK(intSave); + if (swtmr->usTimerID != swtmrID) { + SWTMR_UNLOCK(intSave); + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + switch (swtmr->ucState) { + case OS_SWTMR_STATUS_UNUSED: + ret = LOS_ERRNO_SWTMR_NOT_CREATED; + break; + /* + * If the status of swtmr is timing, it should stop the swtmr first, + * then start the swtmr again. + */ + case OS_SWTMR_STATUS_TICKING: + OsSwtmrStop(swtmr); + /* fall-through */ + case OS_SWTMR_STATUS_CREATED: + swtmr->startTime = OsGetCurrSchedTimeCycle(); + OsSwtmrStart(swtmr->startTime, swtmr); + break; + default: + ret = LOS_ERRNO_SWTMR_STATUS_INVALID; + break; + } + + SWTMR_UNLOCK(intSave); + OsHookCall(LOS_HOOK_TYPE_SWTMR_START, swtmr); + return ret; +} + +LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID) +{ + SWTMR_CTRL_S *swtmr = NULL; + UINT32 intSave; + UINT32 ret = LOS_OK; + UINT16 swtmrCBID; + + if (swtmrID >= OS_SWTMR_MAX_TIMERID) { + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT; + swtmr = g_swtmrCBArray + swtmrCBID; + SWTMR_LOCK(intSave); + + if (swtmr->usTimerID != swtmrID) { + SWTMR_UNLOCK(intSave); + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + switch (swtmr->ucState) { + case OS_SWTMR_STATUS_UNUSED: + ret = LOS_ERRNO_SWTMR_NOT_CREATED; + break; + case OS_SWTMR_STATUS_CREATED: + ret = LOS_ERRNO_SWTMR_NOT_STARTED; + break; + case OS_SWTMR_STATUS_TICKING: + OsSwtmrStop(swtmr); + break; + default: + ret = LOS_ERRNO_SWTMR_STATUS_INVALID; + break; + } + + SWTMR_UNLOCK(intSave); + OsHookCall(LOS_HOOK_TYPE_SWTMR_STOP, swtmr); + return ret; +} + +LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick) +{ + SWTMR_CTRL_S *swtmr = NULL; + UINT32 intSave; + UINT32 ret = LOS_OK; + UINT16 swtmrCBID; + + if (swtmrID >= OS_SWTMR_MAX_TIMERID) { + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + if (tick == NULL) { + return LOS_ERRNO_SWTMR_TICK_PTR_NULL; + } + + swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT; + swtmr = g_swtmrCBArray + swtmrCBID; + SWTMR_LOCK(intSave); + + if (swtmr->usTimerID != swtmrID) { + SWTMR_UNLOCK(intSave); + return LOS_ERRNO_SWTMR_ID_INVALID; + } + switch (swtmr->ucState) { + case OS_SWTMR_STATUS_UNUSED: + ret = LOS_ERRNO_SWTMR_NOT_CREATED; + break; + case OS_SWTMR_STATUS_CREATED: + ret = LOS_ERRNO_SWTMR_NOT_STARTED; + break; + case OS_SWTMR_STATUS_TICKING: + *tick = OsSwtmrTimeGet(swtmr); + break; + default: + ret = LOS_ERRNO_SWTMR_STATUS_INVALID; + break; + } + SWTMR_UNLOCK(intSave); + return ret; +} + +LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID) +{ + SWTMR_CTRL_S *swtmr = NULL; + UINT32 intSave; + UINT32 ret = LOS_OK; + UINT16 swtmrCBID; + + if (swtmrID >= OS_SWTMR_MAX_TIMERID) { + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT; + swtmr = g_swtmrCBArray + swtmrCBID; + SWTMR_LOCK(intSave); + + if (swtmr->usTimerID != swtmrID) { + SWTMR_UNLOCK(intSave); + return LOS_ERRNO_SWTMR_ID_INVALID; + } + + switch (swtmr->ucState) { + case OS_SWTMR_STATUS_UNUSED: + ret = LOS_ERRNO_SWTMR_NOT_CREATED; + break; + case OS_SWTMR_STATUS_TICKING: + OsSwtmrStop(swtmr); + /* fall-through */ + case OS_SWTMR_STATUS_CREATED: + OsSwtmrDelete(swtmr); + break; + default: + ret = LOS_ERRNO_SWTMR_STATUS_INVALID; + break; + } + + SWTMR_UNLOCK(intSave); + OsHookCall(LOS_HOOK_TYPE_SWTMR_DELETE, swtmr); + return ret; +} + +#endif /* LOSCFG_BASE_CORE_SWTMR_ENABLE */ diff --git a/core/los_sys.c b/core/los_sys.c new file mode 100644 index 0000000..8a9d373 --- /dev/null +++ b/core/los_sys.c @@ -0,0 +1,72 @@ +/* + * 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_sys_pri.h" +#include "los_sched_pri.h" + + +#define OS_MAX_VALUE 0xFFFFFFFFUL + +LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID) +{ + return OsGetCurrSchedTimeCycle() / OS_CYCLE_PER_TICK; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID) +{ + return g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec) +{ + if (millisec == OS_MAX_VALUE) { + return OS_MAX_VALUE; + } + + return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 tick) +{ + return ((UINT64)tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 OsNS2Tick(UINT64 nanoseconds) +{ + const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND; + + UINT64 ticks = (nanoseconds + nsPerTick - 1) / nsPerTick; + if (ticks > OS_MAX_VALUE) { + ticks = OS_MAX_VALUE; + } + return (UINT32)ticks; +} + diff --git a/core/los_task.c b/core/los_task.c new file mode 100644 index 0000000..67b7ab6 --- /dev/null +++ b/core/los_task.c @@ -0,0 +1,1691 @@ +/* + * 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_task_pri.h" +#include "los_base_pri.h" +#include "los_event_pri.h" +#include "los_exc.h" +#include "los_hw_pri.h" +#include "los_init.h" +#include "los_memstat_pri.h" +#include "los_mp.h" +#include "los_mux_pri.h" +#include "los_sched_pri.h" +#include "los_sem_pri.h" +#include "los_spinlock.h" +#include "los_strncpy_from_user.h" +#include "los_percpu_pri.h" +#include "los_process_pri.h" +#include "los_vm_map.h" +#include "los_vm_syscall.h" +#include "los_signal.h" +#include "los_hook.h" + +#ifdef LOSCFG_KERNEL_CPUP +#include "los_cpup_pri.h" +#endif +#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE +#include "los_swtmr_pri.h" +#endif +#ifdef LOSCFG_KERNEL_LITEIPC +#include "hm_liteipc.h" +#endif +#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK +#include "los_oom.h" +#endif + +#if (LOSCFG_BASE_CORE_TSK_LIMIT <= 0) +#error "task maxnum cannot be zero" +#endif /* LOSCFG_BASE_CORE_TSK_LIMIT <= 0 */ + +LITE_OS_SEC_BSS LosTaskCB *g_taskCBArray; +LITE_OS_SEC_BSS LOS_DL_LIST g_losFreeTask; +LITE_OS_SEC_BSS LOS_DL_LIST g_taskRecycleList; +LITE_OS_SEC_BSS UINT32 g_taskMaxNum; +LITE_OS_SEC_BSS UINT32 g_taskScheduled; /* one bit for each cores */ +LITE_OS_SEC_BSS EVENT_CB_S g_resourceEvent; +/* spinlock for task module, only available on SMP mode */ +LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_taskSpin); + +STATIC VOID OsConsoleIDSetHook(UINT32 param1, + UINT32 param2) __attribute__((weakref("OsSetConsoleID"))); + +#define OS_CHECK_TASK_BLOCK (OS_TASK_STATUS_DELAY | \ + OS_TASK_STATUS_PENDING | \ + OS_TASK_STATUS_SUSPENDED) + +/* temp task blocks for booting procedure */ +LITE_OS_SEC_BSS STATIC LosTaskCB g_mainTask[LOSCFG_KERNEL_CORE_NUM]; + +LosTaskCB *OsGetMainTask() +{ + return (LosTaskCB *)(g_mainTask + ArchCurrCpuid()); +} + +VOID OsSetMainTask() +{ + UINT32 i; + CHAR *name = "osMain"; + + for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) { + g_mainTask[i].taskStatus = OS_TASK_STATUS_UNUSED; + g_mainTask[i].taskID = LOSCFG_BASE_CORE_TSK_LIMIT; + g_mainTask[i].priority = OS_TASK_PRIORITY_LOWEST; +#ifdef LOSCFG_KERNEL_SMP_LOCKDEP + g_mainTask[i].lockDep.lockDepth = 0; + g_mainTask[i].lockDep.waitLock = NULL; +#endif + (VOID)strncpy_s(g_mainTask[i].taskName, OS_TCB_NAME_LEN, name, OS_TCB_NAME_LEN - 1); + LOS_ListInit(&g_mainTask[i].lockList); + } +} + +LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID) +{ + while (1) { + WFI; + } +} + +STATIC INLINE VOID OsInsertTCBToFreeList(LosTaskCB *taskCB) +{ + UINT32 taskID = taskCB->taskID; + (VOID)memset_s(taskCB, sizeof(LosTaskCB), 0, sizeof(LosTaskCB)); + taskCB->taskID = taskID; + taskCB->taskStatus = OS_TASK_STATUS_UNUSED; + taskCB->processID = OS_INVALID_VALUE; + LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); +} + +LITE_OS_SEC_TEXT_INIT VOID OsTaskJoinPostUnsafe(LosTaskCB *taskCB) +{ + LosTaskCB *resumedTask = NULL; + + if (taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) { + if (!LOS_ListEmpty(&taskCB->joinList)) { + resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(taskCB->joinList))); + OsTaskWakeClearPendMask(resumedTask); + OsSchedTaskWake(resumedTask); + } + taskCB->taskStatus &= ~OS_TASK_FLAG_PTHREAD_JOIN; + } + taskCB->taskStatus |= OS_TASK_STATUS_EXIT; +} + +LITE_OS_SEC_TEXT UINT32 OsTaskJoinPendUnsafe(LosTaskCB *taskCB) +{ + LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); + if (!(processCB->processStatus & OS_PROCESS_STATUS_RUNNING)) { + return LOS_EPERM; + } + + if (taskCB->taskStatus & OS_TASK_STATUS_INIT) { + return LOS_EINVAL; + } + + if ((taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) && LOS_ListEmpty(&taskCB->joinList)) { + OsTaskWaitSetPendMask(OS_TASK_WAIT_JOIN, taskCB->taskID, LOS_WAIT_FOREVER); + return OsSchedTaskWait(&taskCB->joinList, LOS_WAIT_FOREVER, TRUE); + } else if (taskCB->taskStatus & OS_TASK_STATUS_EXIT) { + return LOS_OK; + } + + return LOS_EINVAL; +} + +LITE_OS_SEC_TEXT UINT32 OsTaskSetDetachUnsafe(LosTaskCB *taskCB) +{ + LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); + if (!(processCB->processStatus & OS_PROCESS_STATUS_RUNNING)) { + return LOS_EPERM; + } + + if (taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) { + if (LOS_ListEmpty(&(taskCB->joinList))) { + LOS_ListDelete(&(taskCB->joinList)); + taskCB->taskStatus &= ~OS_TASK_FLAG_PTHREAD_JOIN; + taskCB->taskStatus |= OS_TASK_FLAG_DETACHED; + return LOS_OK; + } + /* This error code has a special purpose and is not allowed to appear again on the interface */ + return LOS_ESRCH; + } + + return LOS_EINVAL; +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID) +{ + UINT32 index; + UINT32 size; + UINT32 ret; + + g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT; + size = (g_taskMaxNum + 1) * sizeof(LosTaskCB); + /* + * This memory is resident memory and is used to save the system resources + * of task control block and will not be freed. + */ + g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size); + if (g_taskCBArray == NULL) { + ret = LOS_ERRNO_TSK_NO_MEMORY; + goto EXIT; + } + (VOID)memset_s(g_taskCBArray, size, 0, size); + + LOS_ListInit(&g_losFreeTask); + LOS_ListInit(&g_taskRecycleList); + for (index = 0; index < g_taskMaxNum; index++) { + g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED; + g_taskCBArray[index].taskID = index; + LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList); + } + + ret = OsSchedInit(); + +EXIT: + if (ret != LOS_OK) { + PRINT_ERR("OsTaskInit error\n"); + } + return ret; +} + +UINT32 OsGetIdleTaskId(VOID) +{ + Percpu *perCpu = OsPercpuGet(); + return perCpu->idleTaskID; +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsIdleTaskCreate(VOID) +{ + UINT32 ret; + TSK_INIT_PARAM_S taskInitParam; + Percpu *perCpu = OsPercpuGet(); + UINT32 *idleTaskID = &perCpu->idleTaskID; + + (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); + taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsIdleTask; + taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE; + taskInitParam.pcName = "Idle"; + taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST; + taskInitParam.processID = OsGetIdleProcessID(); +#ifdef LOSCFG_KERNEL_SMP + taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid()); +#endif + ret = LOS_TaskCreateOnly(idleTaskID, &taskInitParam); + LosTaskCB *idleTask = OS_TCB_FROM_TID(*idleTaskID); + idleTask->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK; + OsSchedSetIdleTaskSchedParam(idleTask); + + return ret; +} + +/* + * Description : get id of current running task. + * Return : task id + */ +LITE_OS_SEC_TEXT UINT32 LOS_CurTaskIDGet(VOID) +{ + LosTaskCB *runTask = OsCurrTaskGet(); + + if (runTask == NULL) { + return LOS_ERRNO_TSK_ID_INVALID; + } + return runTask->taskID; +} + +LITE_OS_SEC_TEXT VOID OsTaskToExit(LosTaskCB *taskCB, UINT32 status) +{ + UINT32 intSave; + + LosProcessCB *runProcess = OS_PCB_FROM_PID(taskCB->processID); + LosTaskCB *mainTask = OS_TCB_FROM_TID(runProcess->threadGroupID); + if (mainTask == taskCB) { + OsTaskExitGroup(status); + } + + SCHEDULER_LOCK(intSave); + + if (runProcess->threadNumber == 1) { /* 1: The last task of the process exits */ + SCHEDULER_UNLOCK(intSave); + (VOID)OsProcessExit(taskCB, status); + return; + } + + /* The thread being killed must be able to exit automatically and will have the detached property */ + OsTaskJoinPostUnsafe(taskCB); + + if (taskCB->taskStatus & (OS_TASK_FLAG_DETACHED | OS_TASK_FLAG_EXIT_KILL)) { + UINT32 ret = OsTaskDeleteUnsafe(taskCB, status, intSave); + LOS_Panic("Task delete failed! ERROR : 0x%x\n", ret); + } + + OsSchedResched(); + SCHEDULER_UNLOCK(intSave); + return; +} + +/* + * Description : All task entry + * Input : taskID --- The ID of the task to be run + */ +LITE_OS_SEC_TEXT_INIT VOID OsTaskEntry(UINT32 taskID) +{ + LosTaskCB *taskCB = NULL; + + LOS_ASSERT(!OS_TID_CHECK_INVALID(taskID)); + + /* + * task scheduler needs to be protected throughout the whole process + * from interrupt and other cores. release task spinlock and enable + * interrupt in sequence at the task entry. + */ + LOS_SpinUnlock(&g_taskSpin); + (VOID)LOS_IntUnLock(); + + taskCB = OS_TCB_FROM_TID(taskID); + taskCB->joinRetval = taskCB->taskEntry(taskCB->args[0], taskCB->args[1], + taskCB->args[2], taskCB->args[3]); /* 2 & 3: just for args array index */ + if (taskCB->taskStatus & OS_TASK_FLAG_DETACHED) { + taskCB->joinRetval = 0; + } + + OsTaskToExit(taskCB, 0); +} + +LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsTaskCreateParamCheck(const UINT32 *taskID, + TSK_INIT_PARAM_S *initParam, VOID **pool) +{ + LosProcessCB *process = NULL; + UINT32 poolSize = OS_SYS_MEM_SIZE; + *pool = (VOID *)m_aucSysMem1; + + if (taskID == NULL) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + if (initParam == NULL) { + return LOS_ERRNO_TSK_PTR_NULL; + } + + process = OS_PCB_FROM_PID(initParam->processID); + if (process->processMode > OS_USER_MODE) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + if (!OsProcessIsUserMode(process)) { + if (initParam->pcName == NULL) { + return LOS_ERRNO_TSK_NAME_EMPTY; + } + } + + if (initParam->pfnTaskEntry == NULL) { + return LOS_ERRNO_TSK_ENTRY_NULL; + } + + if (initParam->usTaskPrio > OS_TASK_PRIORITY_LOWEST) { + return LOS_ERRNO_TSK_PRIOR_ERROR; + } + + if (initParam->uwStackSize > poolSize) { + return LOS_ERRNO_TSK_STKSZ_TOO_LARGE; + } + + if (initParam->uwStackSize == 0) { + initParam->uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; + } + initParam->uwStackSize = (UINT32)ALIGN(initParam->uwStackSize, LOSCFG_STACK_POINT_ALIGN_SIZE); + + if (initParam->uwStackSize < LOS_TASK_MIN_STACK_SIZE) { + return LOS_ERRNO_TSK_STKSZ_TOO_SMALL; + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_INIT STATIC VOID OsTaskStackAlloc(VOID **topStack, UINT32 stackSize, VOID *pool) +{ + *topStack = (VOID *)LOS_MemAllocAlign(pool, stackSize, LOSCFG_STACK_POINT_ALIGN_SIZE); +} + +STATIC INLINE UINT32 OsTaskSyncCreate(LosTaskCB *taskCB) +{ +#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC + UINT32 ret = LOS_SemCreate(0, &taskCB->syncSignal); + if (ret != LOS_OK) { + return LOS_ERRNO_TSK_MP_SYNC_RESOURCE; + } +#else + (VOID)taskCB; +#endif + return LOS_OK; +} + +STATIC INLINE VOID OsTaskSyncDestroy(UINT32 syncSignal) +{ +#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC + (VOID)LOS_SemDelete(syncSignal); +#else + (VOID)syncSignal; +#endif +} + +LITE_OS_SEC_TEXT UINT32 OsTaskSyncWait(const LosTaskCB *taskCB) +{ +#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC + UINT32 ret = LOS_OK; + + LOS_ASSERT(LOS_SpinHeld(&g_taskSpin)); + LOS_SpinUnlock(&g_taskSpin); + /* + * gc soft timer works every OS_MP_GC_PERIOD period, to prevent this timer + * triggered right at the timeout has reached, we set the timeout as double + * of the gc peroid. + */ + if (LOS_SemPend(taskCB->syncSignal, OS_MP_GC_PERIOD * 2) != LOS_OK) { + ret = LOS_ERRNO_TSK_MP_SYNC_FAILED; + } + + LOS_SpinLock(&g_taskSpin); + + return ret; +#else + (VOID)taskCB; + return LOS_OK; +#endif +} + +STATIC INLINE VOID OsTaskSyncWake(const LosTaskCB *taskCB) +{ +#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC + (VOID)OsSemPostUnsafe(taskCB->syncSignal, NULL); +#else + (VOID)taskCB; +#endif +} + +STATIC VOID OsTaskKernelResourcesToFree(UINT32 syncSignal, UINTPTR topOfStack) +{ + VOID *poolTmp = (VOID *)m_aucSysMem1; + + OsTaskSyncDestroy(syncSignal); + + (VOID)LOS_MemFree(poolTmp, (VOID *)topOfStack); +} + +LITE_OS_SEC_TEXT VOID OsTaskCBRecycleToFree() +{ + LosTaskCB *taskCB = NULL; + UINT32 intSave; + + SCHEDULER_LOCK(intSave); + while (!LOS_ListEmpty(&g_taskRecycleList)) { + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_taskRecycleList)); + LOS_ListDelete(&taskCB->pendList); + SCHEDULER_UNLOCK(intSave); + + OsTaskResourcesToFree(taskCB); + + SCHEDULER_LOCK(intSave); + } + SCHEDULER_UNLOCK(intSave); +} + +LITE_OS_SEC_TEXT VOID OsTaskResourcesToFree(LosTaskCB *taskCB) +{ + UINT32 syncSignal = LOSCFG_BASE_IPC_SEM_LIMIT; + UINT32 intSave; + UINTPTR topOfStack; + +#ifdef LOSCFG_KERNEL_VM + LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); + if (OsProcessIsUserMode(processCB) && (taskCB->userMapBase != 0)) { + SCHEDULER_LOCK(intSave); + UINT32 mapBase = (UINTPTR)taskCB->userMapBase; + UINT32 mapSize = taskCB->userMapSize; + taskCB->userMapBase = 0; + taskCB->userArea = 0; + SCHEDULER_UNLOCK(intSave); + + LOS_ASSERT(!(processCB->vmSpace == NULL)); + UINT32 ret = OsUnMMap(processCB->vmSpace, (UINTPTR)mapBase, mapSize); + if ((ret != LOS_OK) && (mapBase != 0) && !(processCB->processStatus & OS_PROCESS_STATUS_INIT)) { + PRINT_ERR("process(%u) ummap user task(%u) stack failed! mapbase: 0x%x size :0x%x, error: %d\n", + processCB->processID, taskCB->taskID, mapBase, mapSize, ret); + } + +#ifdef LOSCFG_KERNEL_LITEIPC + LiteIpcRemoveServiceHandle(taskCB); +#endif + } +#endif + + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + topOfStack = taskCB->topOfStack; + taskCB->topOfStack = 0; +#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC + syncSignal = taskCB->syncSignal; + taskCB->syncSignal = LOSCFG_BASE_IPC_SEM_LIMIT; +#endif + OsTaskKernelResourcesToFree(syncSignal, topOfStack); + + SCHEDULER_LOCK(intSave); + OsClearSigInfoTmpList(&(taskCB->sig)); + OsInsertTCBToFreeList(taskCB); + SCHEDULER_UNLOCK(intSave); + } + return; +} + +LITE_OS_SEC_TEXT_INIT STATIC VOID OsTaskCBInitBase(LosTaskCB *taskCB, + const VOID *stackPtr, + const VOID *topStack, + const TSK_INIT_PARAM_S *initParam) +{ + taskCB->stackPointer = (VOID *)stackPtr; + taskCB->args[0] = initParam->auwArgs[0]; /* 0~3: just for args array index */ + taskCB->args[1] = initParam->auwArgs[1]; + taskCB->args[2] = initParam->auwArgs[2]; + taskCB->args[3] = initParam->auwArgs[3]; + taskCB->topOfStack = (UINTPTR)topStack; + taskCB->stackSize = initParam->uwStackSize; + taskCB->priority = initParam->usTaskPrio; + taskCB->taskEntry = initParam->pfnTaskEntry; + taskCB->signal = SIGNAL_NONE; + +#ifdef LOSCFG_KERNEL_SMP + taskCB->currCpu = OS_TASK_INVALID_CPUID; + taskCB->cpuAffiMask = (initParam->usCpuAffiMask) ? + initParam->usCpuAffiMask : LOSCFG_KERNEL_CPU_MASK; +#endif +#ifdef LOSCFG_KERNEL_LITEIPC + LOS_ListInit(&(taskCB->msgListHead)); +#endif + taskCB->policy = (initParam->policy == LOS_SCHED_FIFO) ? LOS_SCHED_FIFO : LOS_SCHED_RR; + taskCB->taskStatus = OS_TASK_STATUS_INIT; + if (initParam->uwResved & OS_TASK_FLAG_DETACHED) { + taskCB->taskStatus |= OS_TASK_FLAG_DETACHED; + } else { + taskCB->taskStatus |= OS_TASK_FLAG_PTHREAD_JOIN; + LOS_ListInit(&taskCB->joinList); + } + + taskCB->futex.index = OS_INVALID_VALUE; + LOS_ListInit(&taskCB->lockList); + SET_SORTLIST_VALUE(&taskCB->sortList, OS_SORT_LINK_INVALID_TIME); +} + +STATIC UINT32 OsTaskCBInit(LosTaskCB *taskCB, const TSK_INIT_PARAM_S *initParam, + const VOID *stackPtr, const VOID *topStack) +{ + UINT32 intSave; + UINT32 ret; + UINT32 numCount; + UINT16 mode; + LosProcessCB *processCB = NULL; + + OsTaskCBInitBase(taskCB, stackPtr, topStack, initParam); + + SCHEDULER_LOCK(intSave); + processCB = OS_PCB_FROM_PID(initParam->processID); + taskCB->processID = processCB->processID; + mode = processCB->processMode; + LOS_ListTailInsert(&(processCB->threadSiblingList), &(taskCB->threadList)); + if (mode == OS_USER_MODE) { + taskCB->userArea = initParam->userParam.userArea; + taskCB->userMapBase = initParam->userParam.userMapBase; + taskCB->userMapSize = initParam->userParam.userMapSize; + OsUserTaskStackInit(taskCB->stackPointer, (UINTPTR)taskCB->taskEntry, initParam->userParam.userSP); + } + + if (!processCB->threadNumber) { + processCB->threadGroupID = taskCB->taskID; + } + processCB->threadNumber++; + + numCount = processCB->threadCount; + processCB->threadCount++; + SCHEDULER_UNLOCK(intSave); + + if (initParam->pcName != NULL) { + ret = (UINT32)OsSetTaskName(taskCB, initParam->pcName, FALSE); + if (ret == LOS_OK) { + return LOS_OK; + } + } + + if (snprintf_s(taskCB->taskName, OS_TCB_NAME_LEN, OS_TCB_NAME_LEN - 1, "thread%u", numCount) < 0) { + return LOS_NOK; + } + return LOS_OK; +} + +LITE_OS_SEC_TEXT LosTaskCB *OsGetFreeTaskCB(VOID) +{ + UINT32 intSave; + LosTaskCB *taskCB = NULL; + + SCHEDULER_LOCK(intSave); + if (LOS_ListEmpty(&g_losFreeTask)) { + SCHEDULER_UNLOCK(intSave); + PRINT_ERR("No idle TCB in the system!\n"); +#ifdef LOSCFG_DEBUG_VERSION + (VOID)OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, NULL, OS_PROCESS_INFO_ALL); +#endif + return NULL; + } + + taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_losFreeTask)); + LOS_ListDelete(LOS_DL_LIST_FIRST(&g_losFreeTask)); + SCHEDULER_UNLOCK(intSave); + + return taskCB; +} + +LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S *initParam) +{ + UINT32 intSave, errRet; + VOID *topStack = NULL; + VOID *stackPtr = NULL; + LosTaskCB *taskCB = NULL; + VOID *pool = NULL; + + errRet = OsTaskCreateParamCheck(taskID, initParam, &pool); + if (errRet != LOS_OK) { + return errRet; + } + + taskCB = OsGetFreeTaskCB(); + if (taskCB == NULL) { + errRet = LOS_ERRNO_TSK_TCB_UNAVAILABLE; + goto LOS_ERREND; + } + + errRet = OsTaskSyncCreate(taskCB); + if (errRet != LOS_OK) { + goto LOS_ERREND_REWIND_TCB; + } + + OsTaskStackAlloc(&topStack, initParam->uwStackSize, pool); + if (topStack == NULL) { + errRet = LOS_ERRNO_TSK_NO_MEMORY; + goto LOS_ERREND_REWIND_SYNC; + } + + stackPtr = OsTaskStackInit(taskCB->taskID, initParam->uwStackSize, topStack, TRUE); + errRet = OsTaskCBInit(taskCB, initParam, stackPtr, topStack); + if (errRet != LOS_OK) { + goto LOS_ERREND_TCB_INIT; + } + if (OsConsoleIDSetHook != NULL) { + OsConsoleIDSetHook(taskCB->taskID, OsCurrTaskGet()->taskID); + } + + *taskID = taskCB->taskID; + OsHookCall(LOS_HOOK_TYPE_TASK_CREATE, taskCB); + return LOS_OK; + +LOS_ERREND_TCB_INIT: + (VOID)LOS_MemFree(pool, topStack); +LOS_ERREND_REWIND_SYNC: +#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC + OsTaskSyncDestroy(taskCB->syncSignal); +#endif +LOS_ERREND_REWIND_TCB: + SCHEDULER_LOCK(intSave); + OsInsertTCBToFreeList(taskCB); + SCHEDULER_UNLOCK(intSave); +LOS_ERREND: + return errRet; +} + +LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam) +{ + UINT32 ret; + UINT32 intSave; + LosTaskCB *taskCB = NULL; + + if (initParam == NULL) { + return LOS_ERRNO_TSK_PTR_NULL; + } + + if (OS_INT_ACTIVE) { + return LOS_ERRNO_TSK_YIELD_IN_INT; + } + + if (OsProcessIsUserMode(OsCurrProcessGet())) { + initParam->processID = OsGetKernelInitProcessID(); + } else { + initParam->processID = OsCurrProcessGet()->processID; + } + initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN; + if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) { + initParam->uwResved = OS_TASK_FLAG_DETACHED; + } + + ret = LOS_TaskCreateOnly(taskID, initParam); + if (ret != LOS_OK) { + return ret; + } + taskCB = OS_TCB_FROM_TID(*taskID); + + SCHEDULER_LOCK(intSave); + OsSchedTaskEnQueue(taskCB); + SCHEDULER_UNLOCK(intSave); + + /* in case created task not running on this core, + schedule or not depends on other schedulers status. */ + LOS_MpSchedule(OS_MP_CPU_ALL); + if (OS_SCHEDULER_ACTIVE) { + LOS_Schedule(); + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID) +{ + UINT32 intSave; + UINT32 errRet; + LosTaskCB *taskCB = NULL; + BOOL needSched = FALSE; + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + + /* clear pending signal */ + taskCB->signal &= ~SIGNAL_SUSPEND; + + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + errRet = LOS_ERRNO_TSK_NOT_CREATED; + OS_GOTO_ERREND(); + } else if (!(taskCB->taskStatus & OS_TASK_STATUS_SUSPENDED)) { + errRet = LOS_ERRNO_TSK_NOT_SUSPENDED; + OS_GOTO_ERREND(); + } + + taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPENDED; + if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) { + OsSchedTaskEnQueue(taskCB); + if (OS_SCHEDULER_ACTIVE) { + needSched = TRUE; + } + } + SCHEDULER_UNLOCK(intSave); + + LOS_MpSchedule(OS_MP_CPU_ALL); + if (needSched) { + LOS_Schedule(); + } + + return LOS_OK; + +LOS_ERREND: + SCHEDULER_UNLOCK(intSave); + return errRet; +} + +/* + * Check if needs to do the suspend operation on the running task. + * Return TRUE, if needs to do the suspension. + * Return FALSE, if meets following circumstances: + * 1. Do the suspension across cores, if SMP is enabled + * 2. Do the suspension when preemption is disabled + * 3. Do the suspension in hard-irq + * then LOS_TaskSuspend will directly return with 'ret' value. + */ +LITE_OS_SEC_TEXT_INIT STATIC BOOL OsTaskSuspendCheckOnRun(LosTaskCB *taskCB, UINT32 *ret) +{ + /* init default out return value */ + *ret = LOS_OK; + +#ifdef LOSCFG_KERNEL_SMP + /* ASYNCHRONIZED. No need to do task lock checking */ + if (taskCB->currCpu != ArchCurrCpuid()) { + taskCB->signal = SIGNAL_SUSPEND; + LOS_MpSchedule(taskCB->currCpu); + return FALSE; + } +#endif + + if (!OsPreemptableInSched()) { + /* Suspending the current core's running task */ + *ret = LOS_ERRNO_TSK_SUSPEND_LOCKED; + return FALSE; + } + + if (OS_INT_ACTIVE) { + /* suspend running task in interrupt */ + taskCB->signal = SIGNAL_SUSPEND; + return FALSE; + } + + return TRUE; +} + +LITE_OS_SEC_TEXT STATIC UINT32 OsTaskSuspend(LosTaskCB *taskCB) +{ + UINT32 errRet; + UINT16 tempStatus; + + tempStatus = taskCB->taskStatus; + if (tempStatus & OS_TASK_STATUS_UNUSED) { + return LOS_ERRNO_TSK_NOT_CREATED; + } + + if (tempStatus & OS_TASK_STATUS_SUSPENDED) { + return LOS_ERRNO_TSK_ALREADY_SUSPENDED; + } + + if ((tempStatus & OS_TASK_STATUS_RUNNING) && + !OsTaskSuspendCheckOnRun(taskCB, &errRet)) { + return errRet; + } + + if (tempStatus & OS_TASK_STATUS_READY) { + OsSchedTaskDeQueue(taskCB); + } + + taskCB->taskStatus |= OS_TASK_STATUS_SUSPENDED; + OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB); + if (taskCB == OsCurrTaskGet()) { + OsSchedResched(); + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskID) +{ + UINT32 intSave; + LosTaskCB *taskCB = NULL; + UINT32 errRet; + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + taskCB = OS_TCB_FROM_TID(taskID); + if (taskCB->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) { + return LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK; + } + + SCHEDULER_LOCK(intSave); + errRet = OsTaskSuspend(taskCB); + SCHEDULER_UNLOCK(intSave); + return errRet; +} + +STATIC INLINE VOID OsTaskStatusUnusedSet(LosTaskCB *taskCB) +{ + taskCB->taskStatus |= OS_TASK_STATUS_UNUSED; + taskCB->eventMask = 0; + + OS_MEM_CLEAR(taskCB->taskID); +} + +STATIC INLINE VOID OsTaskReleaseHoldLock(LosProcessCB *processCB, LosTaskCB *taskCB) +{ + LosMux *mux = NULL; + UINT32 ret; + + while (!LOS_ListEmpty(&taskCB->lockList)) { + mux = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(&taskCB->lockList), LosMux, holdList); + ret = OsMuxUnlockUnsafe(taskCB, mux, NULL); + if (ret != LOS_OK) { + LOS_ListDelete(&mux->holdList); + PRINT_ERR("mux ulock failed! : %u\n", ret); + } + } + + if (processCB->processMode == OS_USER_MODE) { + OsTaskJoinPostUnsafe(taskCB); + +#ifdef LOSCFG_KERNEL_VM + OsFutexNodeDeleteFromFutexHash(&taskCB->futex, TRUE, NULL, NULL); +#endif + } + + OsTaskSyncWake(taskCB); +} + +LITE_OS_SEC_TEXT VOID OsRunTaskToDelete(LosTaskCB *runTask) +{ + LosProcessCB *processCB = OS_PCB_FROM_PID(runTask->processID); + + OsTaskReleaseHoldLock(processCB, runTask); + OsTaskStatusUnusedSet(runTask); + + LOS_ListDelete(&runTask->threadList); + processCB->threadNumber--; + LOS_ListTailInsert(&g_taskRecycleList, &runTask->pendList); + OsEventWriteUnsafe(&g_resourceEvent, OS_RESOURCE_EVENT_FREE, FALSE, NULL); + + OsSchedResched(); + return; +} + +/* + * Check if needs to do the delete operation on the running task. + * Return TRUE, if needs to do the deletion. + * Return FALSE, if meets following circumstances: + * 1. Do the deletion across cores, if SMP is enabled + * 2. Do the deletion when preemption is disabled + * 3. Do the deletion in hard-irq + * then LOS_TaskDelete will directly return with 'ret' value. + */ +STATIC BOOL OsRunTaskToDeleteCheckOnRun(LosTaskCB *taskCB, UINT32 *ret) +{ + /* init default out return value */ + *ret = LOS_OK; + +#ifdef LOSCFG_KERNEL_SMP + /* ASYNCHRONIZED. No need to do task lock checking */ + if (taskCB->currCpu != ArchCurrCpuid()) { + /* + * the task is running on another cpu. + * mask the target task with "kill" signal, and trigger mp schedule + * which might not be essential but the deletion could more in time. + */ + taskCB->signal = SIGNAL_KILL; + LOS_MpSchedule(taskCB->currCpu); + *ret = OsTaskSyncWait(taskCB); + return FALSE; + } +#endif + + if (!OsPreemptableInSched()) { + /* If the task is running and scheduler is locked then you can not delete it */ + *ret = LOS_ERRNO_TSK_DELETE_LOCKED; + return FALSE; + } + + if (OS_INT_ACTIVE) { + /* + * delete running task in interrupt. + * mask "kill" signal and later deletion will be handled. + */ + taskCB->signal = SIGNAL_KILL; + return FALSE; + } + + return TRUE; +} + +STATIC VOID OsTaskDeleteInactive(LosProcessCB *processCB, LosTaskCB *taskCB) +{ + LosMux *mux = (LosMux *)taskCB->taskMux; + UINT16 taskStatus = taskCB->taskStatus; + + LOS_ASSERT(!(taskStatus & OS_TASK_STATUS_RUNNING)); + + OsTaskReleaseHoldLock(processCB, taskCB); + + OsSchedTaskExit(taskCB); + if (taskStatus & OS_TASK_STATUS_PENDING) { + if (LOS_MuxIsValid(mux) == TRUE) { + OsMuxBitmapRestore(mux, taskCB, (LosTaskCB *)mux->owner); + } + } + + OsTaskStatusUnusedSet(taskCB); + + LOS_ListDelete(&taskCB->threadList); + processCB->threadNumber--; + LOS_ListTailInsert(&g_taskRecycleList, &taskCB->pendList); + return; +} + +LITE_OS_SEC_TEXT UINT32 OsTaskDeleteUnsafe(LosTaskCB *taskCB, UINT32 status, UINT32 intSave) +{ + LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID); + UINT32 mode = processCB->processMode; + UINT32 errRet = LOS_OK; + + if (taskCB->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) { + errRet = LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK; + goto EXIT; + } + + if ((taskCB->taskStatus & OS_TASK_STATUS_RUNNING) && !OsRunTaskToDeleteCheckOnRun(taskCB, &errRet)) { + goto EXIT; + } + + if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) { + OsTaskDeleteInactive(processCB, taskCB); + SCHEDULER_UNLOCK(intSave); + OsWriteResourceEvent(OS_RESOURCE_EVENT_FREE); + return errRet; + } + OsHookCall(LOS_HOOK_TYPE_TASK_DELETE, taskCB); + if (mode == OS_USER_MODE) { + SCHEDULER_UNLOCK(intSave); + OsTaskResourcesToFree(taskCB); + SCHEDULER_LOCK(intSave); + } + +#ifdef LOSCFG_KERNEL_SMP + LOS_ASSERT(OsPercpuGet()->taskLockCnt == 1); +#else + LOS_ASSERT(OsPercpuGet()->taskLockCnt == 0); +#endif + OsRunTaskToDelete(taskCB); + +EXIT: + SCHEDULER_UNLOCK(intSave); + return errRet; +} + +LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskDelete(UINT32 taskID) +{ + UINT32 intSave; + UINT32 ret; + LosTaskCB *taskCB = NULL; + LosProcessCB *processCB = NULL; + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + if (OS_INT_ACTIVE) { + return LOS_ERRNO_TSK_YIELD_IN_INT; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + ret = LOS_ERRNO_TSK_NOT_CREATED; + OS_GOTO_ERREND(); + } + + if (taskCB->taskStatus & (OS_TASK_FLAG_SYSTEM_TASK | OS_TASK_FLAG_NO_DELETE)) { + SCHEDULER_UNLOCK(intSave); + OsBackTrace(); + return LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK; + } + + processCB = OS_PCB_FROM_PID(taskCB->processID); + if (processCB->threadNumber == 1) { /* 1: The last task of the process exits */ + if (processCB == OsCurrProcessGet()) { + SCHEDULER_UNLOCK(intSave); + OsProcessExit(taskCB, OS_PRO_EXIT_OK); + return LOS_OK; + } + + ret = LOS_ERRNO_TSK_ID_INVALID; + OS_GOTO_ERREND(); + } + + return OsTaskDeleteUnsafe(taskCB, OS_PRO_EXIT_OK, intSave); + +LOS_ERREND: + SCHEDULER_UNLOCK(intSave); + return ret; +} + +LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick) +{ + UINT32 intSave; + LosTaskCB *runTask = NULL; + + if (OS_INT_ACTIVE) { + PRINT_ERR("In interrupt not allow delay task!\n"); + return LOS_ERRNO_TSK_DELAY_IN_INT; + } + + runTask = OsCurrTaskGet(); + if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) { + OsBackTrace(); + return LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK; + } + + if (!OsPreemptable()) { + return LOS_ERRNO_TSK_DELAY_IN_LOCK; + } + OsHookCall(LOS_HOOK_TYPE_TASK_DELAY, tick); + if (tick == 0) { + return LOS_TaskYield(); + } + + SCHEDULER_LOCK(intSave); + OsSchedDelay(runTask, tick); + OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTODELAYEDLIST, runTask); + SCHEDULER_UNLOCK(intSave); + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskPriGet(UINT32 taskID) +{ + UINT32 intSave; + LosTaskCB *taskCB = NULL; + UINT16 priority; + + if (OS_TID_CHECK_INVALID(taskID)) { + return (UINT16)OS_INVALID; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + SCHEDULER_UNLOCK(intSave); + return (UINT16)OS_INVALID; + } + + priority = taskCB->priority; + SCHEDULER_UNLOCK(intSave); + return priority; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskPriSet(UINT32 taskID, UINT16 taskPrio) +{ + UINT32 intSave; + LosTaskCB *taskCB = NULL; + + if (taskPrio > OS_TASK_PRIORITY_LOWEST) { + return LOS_ERRNO_TSK_PRIOR_ERROR; + } + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + taskCB = OS_TCB_FROM_TID(taskID); + if (taskCB->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) { + return LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK; + } + + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + SCHEDULER_UNLOCK(intSave); + return LOS_ERRNO_TSK_NOT_CREATED; + } + + BOOL isReady = OsSchedModifyTaskSchedParam(taskCB, taskCB->policy, taskPrio); + SCHEDULER_UNLOCK(intSave); + + LOS_MpSchedule(OS_MP_CPU_ALL); + if (isReady && OS_SCHEDULER_ACTIVE) { + LOS_Schedule(); + } + return LOS_OK; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CurTaskPriSet(UINT16 taskPrio) +{ + return LOS_TaskPriSet(OsCurrTaskGet()->taskID, taskPrio); +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskYield(VOID) +{ + UINT32 intSave; + + if (OS_INT_ACTIVE) { + return LOS_ERRNO_TSK_YIELD_IN_INT; + } + + if (!OsPreemptable()) { + return LOS_ERRNO_TSK_YIELD_IN_LOCK; + } + + LosTaskCB *runTask = OsCurrTaskGet(); + if (OS_TID_CHECK_INVALID(runTask->taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + SCHEDULER_LOCK(intSave); + /* reset timeslice of yielded task */ + OsSchedYield(); + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskLock(VOID) +{ + UINT32 intSave; + + intSave = LOS_IntLock(); + OsCpuSchedLock(OsPercpuGet()); + LOS_IntRestore(intSave); +} + +LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskUnlock(VOID) +{ + OsCpuSchedUnlock(OsPercpuGet(), LOS_IntLock()); +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskInfoGet(UINT32 taskID, TSK_INFO_S *taskInfo) +{ + UINT32 intSave; + LosTaskCB *taskCB = NULL; + + if (taskInfo == NULL) { + return LOS_ERRNO_TSK_PTR_NULL; + } + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + SCHEDULER_UNLOCK(intSave); + return LOS_ERRNO_TSK_NOT_CREATED; + } + + if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING) || OS_INT_ACTIVE) { + taskInfo->uwSP = (UINTPTR)taskCB->stackPointer; + } else { + taskInfo->uwSP = ArchSPGet(); + } + + taskInfo->usTaskStatus = taskCB->taskStatus; + taskInfo->usTaskPrio = taskCB->priority; + taskInfo->uwStackSize = taskCB->stackSize; + taskInfo->uwTopOfStack = taskCB->topOfStack; + taskInfo->uwEventMask = taskCB->eventMask; + taskInfo->taskEvent = taskCB->taskEvent; + taskInfo->pTaskMux = taskCB->taskMux; + taskInfo->uwTaskID = taskID; + + if (strncpy_s(taskInfo->acName, LOS_TASK_NAMELEN, taskCB->taskName, LOS_TASK_NAMELEN - 1) != EOK) { + PRINT_ERR("Task name copy failed!\n"); + } + taskInfo->acName[LOS_TASK_NAMELEN - 1] = '\0'; + + taskInfo->uwBottomOfStack = TRUNCATE(((UINTPTR)taskCB->topOfStack + taskCB->stackSize), + OS_TASK_STACK_ADDR_ALIGN); + taskInfo->uwCurrUsed = (UINT32)(taskInfo->uwBottomOfStack - taskInfo->uwSP); + + taskInfo->bOvf = OsStackWaterLineGet((const UINTPTR *)taskInfo->uwBottomOfStack, + (const UINTPTR *)taskInfo->uwTopOfStack, &taskInfo->uwPeakUsed); + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +LITE_OS_SEC_TEXT BOOL OsTaskCpuAffiSetUnsafe(UINT32 taskID, UINT16 newCpuAffiMask, UINT16 *oldCpuAffiMask) +{ +#ifdef LOSCFG_KERNEL_SMP + LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID); + + taskCB->cpuAffiMask = newCpuAffiMask; + *oldCpuAffiMask = CPUID_TO_AFFI_MASK(taskCB->currCpu); + if (!((*oldCpuAffiMask) & newCpuAffiMask)) { + taskCB->signal = SIGNAL_AFFI; + return TRUE; + } +#else + (VOID)taskID; + (VOID)newCpuAffiMask; + (VOID)oldCpuAffiMask; +#endif /* LOSCFG_KERNEL_SMP */ + return FALSE; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskCpuAffiSet(UINT32 taskID, UINT16 cpuAffiMask) +{ + LosTaskCB *taskCB = NULL; + BOOL needSched = FALSE; + UINT32 intSave; + UINT16 currCpuMask; + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ERRNO_TSK_ID_INVALID; + } + + if (!(cpuAffiMask & LOSCFG_KERNEL_CPU_MASK)) { + return LOS_ERRNO_TSK_CPU_AFFINITY_MASK_ERR; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + SCHEDULER_UNLOCK(intSave); + return LOS_ERRNO_TSK_NOT_CREATED; + } + needSched = OsTaskCpuAffiSetUnsafe(taskID, cpuAffiMask, &currCpuMask); + + SCHEDULER_UNLOCK(intSave); + if (needSched && OS_SCHEDULER_ACTIVE) { + LOS_MpSchedule(currCpuMask); + LOS_Schedule(); + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskCpuAffiGet(UINT32 taskID) +{ +#ifdef LOSCFG_KERNEL_SMP +#define INVALID_CPU_AFFI_MASK 0 + LosTaskCB *taskCB = NULL; + UINT16 cpuAffiMask; + UINT32 intSave; + + if (OS_TID_CHECK_INVALID(taskID)) { + return INVALID_CPU_AFFI_MASK; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + SCHEDULER_UNLOCK(intSave); + return INVALID_CPU_AFFI_MASK; + } + + cpuAffiMask = taskCB->cpuAffiMask; + SCHEDULER_UNLOCK(intSave); + + return cpuAffiMask; +#else + (VOID)taskID; + return 1; +#endif +} + +/* + * Description : Process pending signals tagged by others cores + */ +LITE_OS_SEC_TEXT_MINOR VOID OsTaskProcSignal(VOID) +{ + UINT32 intSave, ret; + + /* + * private and uninterruptable, no protection needed. + * while this task is always running when others cores see it, + * so it keeps receiving signals while follow code executing. + */ + LosTaskCB *runTask = OsCurrTaskGet(); + if (runTask->signal == SIGNAL_NONE) { + return; + } + + if (runTask->signal & SIGNAL_KILL) { + /* + * clear the signal, and do the task deletion. if the signaled task has been + * scheduled out, then this deletion will wait until next run. + */ + SCHEDULER_LOCK(intSave); + runTask->signal = SIGNAL_NONE; + ret = OsTaskDeleteUnsafe(runTask, OS_PRO_EXIT_OK, intSave); + if (ret) { + PRINT_ERR("Task proc signal delete task(%u) failed err:0x%x\n", runTask->taskID, ret); + } + } else if (runTask->signal & SIGNAL_SUSPEND) { + runTask->signal &= ~SIGNAL_SUSPEND; + + /* suspend killed task may fail, ignore the result */ + (VOID)LOS_TaskSuspend(runTask->taskID); +#ifdef LOSCFG_KERNEL_SMP + } else if (runTask->signal & SIGNAL_AFFI) { + runTask->signal &= ~SIGNAL_AFFI; + + /* pri-queue has updated, notify the target cpu */ + LOS_MpSchedule((UINT32)runTask->cpuAffiMask); +#endif + } +} + +LITE_OS_SEC_TEXT INT32 OsSetTaskName(LosTaskCB *taskCB, const CHAR *name, BOOL setPName) +{ + UINT32 intSave; + errno_t err; + LosProcessCB *processCB = NULL; + const CHAR *namePtr = NULL; + CHAR nameBuff[OS_TCB_NAME_LEN] = { 0 }; + + if ((taskCB == NULL) || (name == NULL)) { + return EINVAL; + } + + if (LOS_IsUserAddress((VADDR_T)(UINTPTR)name)) { + err = LOS_StrncpyFromUser(nameBuff, (const CHAR *)name, OS_TCB_NAME_LEN); + if (err < 0) { + return -err; + } + namePtr = nameBuff; + } else { + namePtr = name; + } + + SCHEDULER_LOCK(intSave); + + err = strncpy_s(taskCB->taskName, OS_TCB_NAME_LEN, (VOID *)namePtr, OS_TCB_NAME_LEN - 1); + if (err != EOK) { + err = EINVAL; + goto EXIT; + } + + err = LOS_OK; + processCB = OS_PCB_FROM_PID(taskCB->processID); + /* if thread is main thread, then set processName as taskName */ + if ((taskCB->taskID == processCB->threadGroupID) && (setPName == TRUE)) { + err = (INT32)OsSetProcessName(processCB, (const CHAR *)taskCB->taskName); + if (err != LOS_OK) { + err = EINVAL; + } + } + +EXIT: + SCHEDULER_UNLOCK(intSave); + return err; +} + +STATIC VOID OsExitGroupActiveTaskKilled(LosProcessCB *processCB, LosTaskCB *taskCB) +{ + INT32 ret; + + taskCB->taskStatus |= OS_TASK_FLAG_EXIT_KILL; +#ifdef LOSCFG_KERNEL_SMP + /* The other core that the thread is running on and is currently running in a non-system call */ + if (!taskCB->sig.sigIntLock && (taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) { + taskCB->signal = SIGNAL_KILL; + LOS_MpSchedule(taskCB->currCpu); + } else +#endif +#ifdef LOSCFG_KERNEL_VM + { + ret = OsTaskKillUnsafe(taskCB->taskID, SIGKILL); + if (ret != LOS_OK) { + PRINT_ERR("pid %u exit, Exit task group %u kill %u failed! ERROR: %d\n", + taskCB->processID, OsCurrTaskGet()->taskID, taskCB->taskID, ret); + } + } +#endif + + if (!(taskCB->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN)) { + taskCB->taskStatus |= OS_TASK_FLAG_PTHREAD_JOIN; + LOS_ListInit(&taskCB->joinList); + } + + ret = OsTaskJoinPendUnsafe(taskCB); + if (ret != LOS_OK) { + PRINT_ERR("pid %u exit, Exit task group %u to wait others task %u(0x%x) exit failed! ERROR: %d\n", + taskCB->processID, OsCurrTaskGet()->taskID, taskCB->taskID, taskCB->taskStatus, ret); + } +} + +LITE_OS_SEC_TEXT VOID OsTaskExitGroup(UINT32 status) +{ + UINT32 intSave; + + LosProcessCB *processCB = OsCurrProcessGet(); + LosTaskCB *currTask = OsCurrTaskGet(); + SCHEDULER_LOCK(intSave); + if ((processCB->processStatus & OS_PROCESS_FLAG_EXIT) || !OsProcessIsUserMode(processCB)) { + SCHEDULER_UNLOCK(intSave); + return; + } + + processCB->processStatus |= OS_PROCESS_FLAG_EXIT; + processCB->threadGroupID = currTask->taskID; + + LOS_DL_LIST *list = &processCB->threadSiblingList; + LOS_DL_LIST *head = list; + do { + LosTaskCB *taskCB = LOS_DL_LIST_ENTRY(list->pstNext, LosTaskCB, threadList); + if ((taskCB->taskStatus & (OS_TASK_STATUS_INIT | OS_TASK_STATUS_EXIT) || + ((taskCB->taskStatus & OS_TASK_STATUS_READY) && !taskCB->sig.sigIntLock)) && + !(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) { + OsTaskDeleteInactive(processCB, taskCB); + } else { + if (taskCB != currTask) { + OsExitGroupActiveTaskKilled(processCB, taskCB); + } else { + /* Skip the current task */ + list = list->pstNext; + } + } + } while (head != list->pstNext); + + SCHEDULER_UNLOCK(intSave); + + LOS_ASSERT(processCB->threadNumber == 1); + return; +} + +LITE_OS_SEC_TEXT VOID OsExecDestroyTaskGroup(VOID) +{ + OsTaskExitGroup(OS_PRO_EXIT_OK); + OsTaskCBRecycleToFree(); +} + +UINT32 OsUserTaskOperatePermissionsCheck(LosTaskCB *taskCB) +{ + return OsUserProcessOperatePermissionsCheck(taskCB, OsCurrProcessGet()->processID); +} + +UINT32 OsUserProcessOperatePermissionsCheck(LosTaskCB *taskCB, UINT32 processID) +{ + if (taskCB == NULL) { + return LOS_EINVAL; + } + + if (processID == OS_INVALID_VALUE) { + return OS_INVALID_VALUE; + } + + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + return LOS_EINVAL; + } + + if (processID != taskCB->processID) { + return LOS_EPERM; + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsCreateUserTaskParamCheck(UINT32 processID, TSK_INIT_PARAM_S *param) +{ + UserTaskParam *userParam = NULL; + + if (param == NULL) { + return OS_INVALID_VALUE; + } + + userParam = ¶m->userParam; + if ((processID == OS_INVALID_VALUE) && !LOS_IsUserAddress(userParam->userArea)) { + return OS_INVALID_VALUE; + } + + if (!LOS_IsUserAddress((UINTPTR)param->pfnTaskEntry)) { + return OS_INVALID_VALUE; + } + + if (userParam->userMapBase && !LOS_IsUserAddressRange(userParam->userMapBase, userParam->userMapSize)) { + return OS_INVALID_VALUE; + } + + if (!LOS_IsUserAddress(userParam->userSP)) { + return OS_INVALID_VALUE; + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT_INIT UINT32 OsCreateUserTask(UINT32 processID, TSK_INIT_PARAM_S *initParam) +{ + LosProcessCB *processCB = NULL; + UINT32 taskID; + UINT32 ret; + UINT32 intSave; + + ret = OsCreateUserTaskParamCheck(processID, initParam); + if (ret != LOS_OK) { + return ret; + } + + initParam->uwStackSize = OS_USER_TASK_SYSCALL_STACK_SIZE; + initParam->usTaskPrio = OS_TASK_PRIORITY_LOWEST; + initParam->policy = LOS_SCHED_RR; + if (processID == OS_INVALID_VALUE) { + SCHEDULER_LOCK(intSave); + processCB = OsCurrProcessGet(); + initParam->processID = processCB->processID; + initParam->consoleID = processCB->consoleID; + SCHEDULER_UNLOCK(intSave); + } else { + processCB = OS_PCB_FROM_PID(processID); + if (!(processCB->processStatus & (OS_PROCESS_STATUS_INIT | OS_PROCESS_STATUS_RUNNING))) { + return OS_INVALID_VALUE; + } + initParam->processID = processID; + initParam->consoleID = 0; + } + + ret = LOS_TaskCreateOnly(&taskID, initParam); + if (ret != LOS_OK) { + return OS_INVALID_VALUE; + } + + return taskID; +} + +LITE_OS_SEC_TEXT INT32 LOS_GetTaskScheduler(INT32 taskID) +{ + UINT32 intSave; + LosTaskCB *taskCB = NULL; + INT32 policy; + + if (OS_TID_CHECK_INVALID(taskID)) { + return -LOS_EINVAL; + } + + taskCB = OS_TCB_FROM_TID(taskID); + SCHEDULER_LOCK(intSave); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + policy = -LOS_EINVAL; + OS_GOTO_ERREND(); + } + + policy = taskCB->policy; + +LOS_ERREND: + SCHEDULER_UNLOCK(intSave); + return policy; +} + +LITE_OS_SEC_TEXT INT32 LOS_SetTaskScheduler(INT32 taskID, UINT16 policy, UINT16 priority) +{ + UINT32 intSave; + BOOL needSched = FALSE; + + if (OS_TID_CHECK_INVALID(taskID)) { + return LOS_ESRCH; + } + + if (priority > OS_TASK_PRIORITY_LOWEST) { + return LOS_EINVAL; + } + + if ((policy != LOS_SCHED_FIFO) && (policy != LOS_SCHED_RR)) { + return LOS_EINVAL; + } + + SCHEDULER_LOCK(intSave); + needSched = OsSchedModifyTaskSchedParam(OS_TCB_FROM_TID(taskID), policy, priority); + SCHEDULER_UNLOCK(intSave); + + LOS_MpSchedule(OS_MP_CPU_ALL); + if (needSched && OS_SCHEDULER_ACTIVE) { + LOS_Schedule(); + } + + return LOS_OK; +} + +LITE_OS_SEC_TEXT UINT32 LOS_GetSystemTaskMaximum(VOID) +{ + return g_taskMaxNum; +} + +LITE_OS_SEC_TEXT VOID OsWriteResourceEvent(UINT32 events) +{ + (VOID)LOS_EventWrite(&g_resourceEvent, events); +} + +LITE_OS_SEC_TEXT VOID OsWriteResourceEventUnsafe(UINT32 events) +{ + (VOID)OsEventWriteUnsafe(&g_resourceEvent, events, FALSE, NULL); +} + +STATIC VOID OsResourceRecoveryTask(VOID) +{ + UINT32 ret; + + while (1) { + ret = LOS_EventRead(&g_resourceEvent, OS_RESOURCE_EVENT_MASK, + LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); + if (ret & (OS_RESOURCE_EVENT_FREE | OS_RESOURCE_EVENT_OOM)) { + OsTaskCBRecycleToFree(); + + OsProcessCBRecycleToFree(); + } + +#ifdef LOSCFG_ENABLE_OOM_LOOP_TASK + if (ret & OS_RESOURCE_EVENT_OOM) { + (VOID)OomCheckProcess(); + } +#endif + } +} + +LITE_OS_SEC_TEXT UINT32 OsResourceFreeTaskCreate(VOID) +{ + UINT32 ret; + UINT32 taskID; + TSK_INIT_PARAM_S taskInitParam; + + ret = LOS_EventInit((PEVENT_CB_S)&g_resourceEvent); + if (ret != LOS_OK) { + return LOS_NOK; + } + + (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); + taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsResourceRecoveryTask; + taskInitParam.uwStackSize = OS_TASK_RESOURCE_STATIC_SIZE; + taskInitParam.pcName = "ResourcesTask"; + taskInitParam.usTaskPrio = OS_TASK_RESOURCE_FREE_PRIORITY; + ret = LOS_TaskCreate(&taskID, &taskInitParam); + if (ret == LOS_OK) { + OS_TCB_FROM_TID(taskID)->taskStatus |= OS_TASK_FLAG_NO_DELETE; + } + return ret; +} + +LOS_MODULE_INIT(OsResourceFreeTaskCreate, LOS_INIT_LEVEL_KMOD_TASK); + diff --git a/core/los_tick.c b/core/los_tick.c new file mode 100644 index 0000000..b5c2794 --- /dev/null +++ b/core/los_tick.c @@ -0,0 +1,66 @@ +/* + * 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_tick_pri.h" +#include "los_swtmr_pri.h" +#include "los_sched_pri.h" +#ifdef LOSCFG_KERNEL_VDSO +#include "los_vdso.h" +#endif + + +LITE_OS_SEC_DATA_INIT UINT32 g_sysClock; +LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond; +LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; + +/* spinlock for task module */ +LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); + +/* + * Description : Tick interruption handler + */ +LITE_OS_SEC_TEXT VOID OsTickHandler(VOID) +{ +#ifdef LOSCFG_SCHED_TICK_DEBUG + OsSchedDebugRecordData(); +#endif + +#ifdef LOSCFG_KERNEL_VDSO + OsVdsoTimevalUpdate(); +#endif + +#ifdef LOSCFG_BASE_CORE_TICK_HW_TIME + HalClockIrqClear(); /* diff from every platform */ +#endif + + OsSchedTick(); +} + diff --git a/sched/sched_sq/los_sched.c b/sched/sched_sq/los_sched.c new file mode 100644 index 0000000..dab0291 --- /dev/null +++ b/sched/sched_sq/los_sched.c @@ -0,0 +1,1170 @@ +/* + * 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" +#include "los_hook.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; + OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->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 */ + OsHookCall(LOS_HOOK_TYPE_TASK_SWITCHEDIN, 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; +} + diff --git a/sched/sched_sq/los_sortlink.c b/sched/sched_sq/los_sortlink.c new file mode 100644 index 0000000..9115892 --- /dev/null +++ b/sched/sched_sq/los_sortlink.c @@ -0,0 +1,232 @@ +/* + * 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_sortlink_pri.h" +#include "los_memory.h" +#include "los_exc.h" +#include "los_percpu_pri.h" +#include "los_sched_pri.h" +#include "los_mp.h" + +UINT32 OsSortLinkInit(SortLinkAttribute *sortLinkHeader) +{ + LOS_ListInit(&sortLinkHeader->sortLink); + sortLinkHeader->nodeNum = 0; + return LOS_OK; +} + +STATIC INLINE VOID OsAddNode2SortLink(SortLinkAttribute *sortLinkHeader, SortLinkList *sortList) +{ + LOS_DL_LIST *head = (LOS_DL_LIST *)&sortLinkHeader->sortLink; + + if (LOS_ListEmpty(head)) { + LOS_ListHeadInsert(head, &sortList->sortLinkNode); + sortLinkHeader->nodeNum++; + return; + } + + SortLinkList *listSorted = LOS_DL_LIST_ENTRY(head->pstNext, SortLinkList, sortLinkNode); + if (listSorted->responseTime > sortList->responseTime) { + LOS_ListAdd(head, &sortList->sortLinkNode); + sortLinkHeader->nodeNum++; + return; + } else if (listSorted->responseTime == sortList->responseTime) { + LOS_ListAdd(head->pstNext, &sortList->sortLinkNode); + sortLinkHeader->nodeNum++; + return; + } + + LOS_DL_LIST *prevNode = head->pstPrev; + do { + listSorted = LOS_DL_LIST_ENTRY(prevNode, SortLinkList, sortLinkNode); + if (listSorted->responseTime <= sortList->responseTime) { + LOS_ListAdd(prevNode, &sortList->sortLinkNode); + sortLinkHeader->nodeNum++; + break; + } + + prevNode = prevNode->pstPrev; + } while (1); +} + +VOID OsDeleteNodeSortLink(SortLinkAttribute *sortLinkHeader, SortLinkList *sortList) +{ + LOS_ListDelete(&sortList->sortLinkNode); + SET_SORTLIST_VALUE(sortList, OS_SORT_LINK_INVALID_TIME); + sortLinkHeader->nodeNum--; +} + +STATIC INLINE UINT64 OsGetSortLinkNextExpireTime(SortLinkAttribute *sortHeader, UINT64 startTime) +{ + LOS_DL_LIST *head = &sortHeader->sortLink; + LOS_DL_LIST *list = head->pstNext; + + if (LOS_ListEmpty(head)) { + return OS_SCHED_MAX_RESPONSE_TIME - OS_TICK_RESPONSE_PRECISION; + } + + SortLinkList *listSorted = LOS_DL_LIST_ENTRY(list, SortLinkList, sortLinkNode); + if (listSorted->responseTime <= (startTime + OS_TICK_RESPONSE_PRECISION)) { + return startTime + OS_TICK_RESPONSE_PRECISION; + } + + return listSorted->responseTime; +} + +STATIC Percpu *OsFindIdleCpu(UINT16 *idleCpuID) +{ + Percpu *idleCpu = OsPercpuGetByID(0); + *idleCpuID = 0; + +#ifdef LOSCFG_KERNEL_SMP + UINT16 cpuID = 1; + UINT32 nodeNum = idleCpu->taskSortLink.nodeNum + idleCpu->swtmrSortLink.nodeNum; + + do { + Percpu *cpu = OsPercpuGetByID(cpuID); + UINT32 temp = cpu->taskSortLink.nodeNum + cpu->swtmrSortLink.nodeNum; + if (nodeNum > temp) { + idleCpu = cpu; + *idleCpuID = cpuID; + } + + cpuID++; + } while (cpuID < LOSCFG_KERNEL_CORE_NUM); +#endif + + return idleCpu; +} + +VOID OsAdd2SortLink(SortLinkList *node, UINT64 startTime, UINT32 waitTicks, SortLinkType type) +{ + UINT32 intSave; + Percpu *cpu = NULL; + SortLinkAttribute *sortLinkHeader = NULL; + SPIN_LOCK_S *spinLock = NULL; + UINT16 idleCpu; + + if (OS_SCHEDULER_ACTIVE) { + cpu = OsFindIdleCpu(&idleCpu); + } else { + idleCpu = ArchCurrCpuid(); + cpu = OsPercpuGet(); + } + + if (type == OS_SORT_LINK_TASK) { + sortLinkHeader = &cpu->taskSortLink; + spinLock = &cpu->taskSortLinkSpin; + } else if (type == OS_SORT_LINK_SWTMR) { + sortLinkHeader = &cpu->swtmrSortLink; + spinLock = &cpu->swtmrSortLinkSpin; + } else { + LOS_Panic("Sort link type error : %u\n", type); + } + + LOS_SpinLockSave(spinLock, &intSave); + SET_SORTLIST_VALUE(node, startTime + (UINT64)waitTicks * OS_CYCLE_PER_TICK); + OsAddNode2SortLink(sortLinkHeader, node); +#ifdef LOSCFG_KERNEL_SMP + node->cpuid = idleCpu; + if (idleCpu != ArchCurrCpuid()) { + LOS_MpSchedule(CPUID_TO_AFFI_MASK(idleCpu)); + } +#endif + LOS_SpinUnlockRestore(spinLock, intSave); +} + +VOID OsDeleteSortLink(SortLinkList *node, SortLinkType type) +{ + UINT32 intSave; +#ifdef LOSCFG_KERNEL_SMP + Percpu *cpu = OsPercpuGetByID(node->cpuid); +#else + Percpu *cpu = OsPercpuGetByID(0); +#endif + + SPIN_LOCK_S *spinLock = NULL; + SortLinkAttribute *sortLinkHeader = NULL; + if (type == OS_SORT_LINK_TASK) { + sortLinkHeader = &cpu->taskSortLink; + spinLock = &cpu->taskSortLinkSpin; + } else if (type == OS_SORT_LINK_SWTMR) { + sortLinkHeader = &cpu->swtmrSortLink; + spinLock = &cpu->swtmrSortLinkSpin; + } else { + LOS_Panic("Sort link type error : %u\n", type); + } + + LOS_SpinLockSave(spinLock, &intSave); + if (node->responseTime != OS_SORT_LINK_INVALID_TIME) { + OsDeleteNodeSortLink(sortLinkHeader, node); + } + LOS_SpinUnlockRestore(spinLock, intSave); +} + +UINT64 OsGetNextExpireTime(UINT64 startTime) +{ + UINT32 intSave; + Percpu *cpu = OsPercpuGet(); + SortLinkAttribute *taskHeader = &cpu->taskSortLink; + SortLinkAttribute *swtmrHeader = &cpu->swtmrSortLink; + + LOS_SpinLockSave(&cpu->taskSortLinkSpin, &intSave); + UINT64 taskExpirTime = OsGetSortLinkNextExpireTime(taskHeader, startTime); + LOS_SpinUnlockRestore(&cpu->taskSortLinkSpin, intSave); + + LOS_SpinLockSave(&cpu->swtmrSortLinkSpin, &intSave); + UINT64 swtmrExpirTime = OsGetSortLinkNextExpireTime(swtmrHeader, startTime); + LOS_SpinUnlockRestore(&cpu->swtmrSortLinkSpin, intSave); + + return (taskExpirTime < swtmrExpirTime) ? taskExpirTime : swtmrExpirTime; +} + +UINT32 OsSortLinkGetTargetExpireTime(const SortLinkList *targetSortList) +{ + UINT64 currTimes = OsGetCurrSchedTimeCycle(); + if (currTimes >= targetSortList->responseTime) { + return 0; + } + + return (UINT32)(targetSortList->responseTime - currTimes) / OS_CYCLE_PER_TICK; +} + +UINT32 OsSortLinkGetNextExpireTime(const SortLinkAttribute *sortLinkHeader) +{ + LOS_DL_LIST *head = (LOS_DL_LIST *)&sortLinkHeader->sortLink; + + if (LOS_ListEmpty(head)) { + return 0; + } + + SortLinkList *listSorted = LOS_DL_LIST_ENTRY(head->pstNext, SortLinkList, sortLinkNode); + return OsSortLinkGetTargetExpireTime(listSorted); +} +