You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ruanjiangongcheng/process1520-2000.c

461 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;//计算 BSS 段(未初始化数据段)的大小 initBssSize//
UINT32 initSize = userInitEnd - userInitTextStart;//计算和整个初始化段(包括 text、data 和 bss的大小 //
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;//检查 userInitTextStart 和 userInitEnd 是否都按页对齐//
}
if ((initSize == 0) || (initSize <= initBssSize)) {
return LOS_EINVAL;//检查 initSize 是否为零或者小于等于 initBssSize如果是则返回错误码 LOS_EINVAL//
}
userText = LOS_PhysPagesAllocContiguous(initSize >> PAGE_SHIFT);
if (userText == NULL) {
return LOS_NOK;//使用 LOS_PhysPagesAllocContiguous 函数为用户空间初始化段分配连续的物理页面,并将地址赋值给 userText//
}
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;//使用 memcpy_s 将初始化段的 text 和 data 部分从 __user_init_load_addr 复制到新分配的 userText 指向的内存区域//
}
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;//使用 LOS_VaddrToPaddrMmap 函数将新分配的物理页面映射到进程的虚拟地址空间//
}
/* 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;//如果存在 BSS 段initBssSize 不为 0则使用 memset_s 函数将 BSS 段的内存清零//
}
}
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;//如果在复制或内存映射过程中发生错误,会跳转到 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, &param);
if (ret != LOS_OK) {
(VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);
goto ERROR;
}
return LOS_OK;//如果一切顺利,函数最后返回 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;//如果分配失败,返回 LOS_ENOMEM 表示内存不足//
}
(VOID)memcpy_s(childCB->user, size, parentCB->user, size);//使用 memcpy_s 将父进程的用户信息复制到子进程//
#endif
return LOS_OK;//返回 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;//如果当前任务支持线程的 join 操作或者是 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);//调用 LOS_TaskCreateOnly 来创建任务,仅创建任务而不立即运行//
if (ret != LOS_OK) {
if (ret == LOS_ERRNO_TSK_TCB_UNAVAILABLE) {
return LOS_EAGAIN;
}
return LOS_ENOMEM;//如果任务创建失败,根据错误类型返回相应的错误码(如 LOS_EAGAIN 表示资源暂时不可用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;
}//根据 flags 中的 CLONE_PARENT 位决定子进程的父进程是当前进程的父进程还是当前进程本身//
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);//调用 OsCopyUser 函数复制用户信息//
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;//如果子进程不是用户模式,直接返回 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;//如果 flags 中的 CLONE_VM 位被设置,表示需要共享虚拟内存空间,那么将父进程的虚拟内存表指针复制给子进程,并返回 LOS_OK//
}
status = LOS_VmSpaceClone(runProcessCB->vmSpace, childProcessCB->vmSpace);
if (status != LOS_OK) {
return LOS_ENOMEM;
}
return LOS_OK;//如果没有设置 CLONE_VM 位,则调用 LOS_VmSpaceClone 函数来克隆父进程的虚拟内存空间给子进程//
}
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;//如果虚拟内存空间克隆失败,返回 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)
{//初始化子进程的进程控制块PCB//
UINT32 ret;
LosProcessCB *run = OsCurrProcessGet();
ret = OsInitPCB(child, run->processMode, OS_PROCESS_PRIORITY_LOWEST, name);
if (ret != LOS_OK) {
return ret;
}//调用 OsInitPCB 来初始化 PCB 的基本信息//
ret = OsCopyParent(flags, child, run);
if (ret != LOS_OK) {
return ret;
}
return OsCopyTask(flags, child, name, sp, size);//继续调用 OsCopyParent 复制父进程的某些资源给子进程,最后调用 OsCopyTask 来复制任务相关的资源//
}
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;
}//如果系统配置了 LOSCFG_KERNEL_LITEIPC则还需要重新初始化 IPC 资源//
#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;//如果配置了 LOSCFG_SECURITY_CAPABILITY还需要复制安全能力//
}
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;//获取一个空闲的 PCB然后通过调用 OsForkInitPCB 初始化 PCB//
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;
}//通过 OsCopyProcessResources 复制资源//
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;//通过 OsChildSetProcessGroupAndSched 设置进程组和调度。如果任何步骤失败,它会跳转到错误处理部分并释放已分配的资源//
ERROR_TASK:
SCHEDULER_LOCK(intSave);
(VOID)OsTaskDeleteUnsafe(OS_TCB_FROM_TID(child->threadGroupID), OS_PRO_EXIT_OK, intSave);//调用来删除已经创建但未能成功完成初始化的子进程的主线程//
ERROR_INIT:
OsDeInitPCB(child);
return -ret;//调用来释放和反初始化进程控制块PCB//
}
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");//检查传入的 flags 参数,并确保没有不支持的标志被设置。如果有不支持的标志,它会打印警告//
}
return OsCopyProcess(cloneFlag & flags, NULL, sp, size);//调用 OsCopyProcess 来实际创建一个新的进程或线程//
}
LITE_OS_SEC_TEXT INT32 LOS_Fork(UINT32 flags, const CHAR *name, const TSK_ENTRY_FUNC entry, UINT32 stackSize)
{//供了一个创建新进程的接口,类似于 UNIX 系统中的 fork 系统调用//
UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | CLONE_VFORK | CLONE_FILES;
if (flags & (~cloneFlag)) {
PRINT_WARN("Clone dont support some flags!\n");
}//检查 flags 参数,确保没有不支持的标志被设置,并添加 CLONE_FILES 标志,以便子进程可以共享文件描述符表//
flags |= CLONE_FILES;
return OsCopyProcess(cloneFlag & flags, name, (UINTPTR)entry, stackSize);
}
#else
LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID)
{
return 0;
}
#endif//OsCopyProcess 函数来创建一个新的进程//
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);//如果条件允许,它会调用 OsTaskExitGroup 和 OsProcessExit 来完成退出流程//
}
LITE_OS_SEC_TEXT INT32 LOS_GetUsedPIDList(UINT32 *pidList, INT32 pidMaxNum)
{//这个函数用于获取当前正在使用的所有进程的 PID 列表//
LosProcessCB *pcb = NULL;
INT32 num = 0;
UINT32 intSave;
UINT32 pid = 1;
if (pidList == NULL) {
return 0;
}//它通过遍历所有可能的 PID 并检查对应的 PCB 是否正在使用来实现//
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;//如果 PCB 正在使用,它将该 PCB 的 PID 添加到 pidList 数组中,并返回找到的 PID 数量//
}
#ifdef LOSCFG_FS_VFS
LITE_OS_SEC_TEXT struct fd_table_s *LOS_GetFdTable(UINT32 pid)
{//返回指定 PID 的进程的文件描述符表//
LosProcessCB *pcb = NULL;
struct files_struct *files = NULL;//它首先检查 PID 是否有效,然后获取对应的 PCB 和文件结构体 files//
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;//如果这些结构体有效,它返回文件描述符表 fdt//
}