您的位置:首页 > 游戏 > 游戏 > 鸿蒙轻内核A核源码分析系列七 进程管理 (3)

鸿蒙轻内核A核源码分析系列七 进程管理 (3)

2024/11/18 8:29:48 来源:https://blog.csdn.net/maniuT/article/details/139664197  浏览:    关键词:鸿蒙轻内核A核源码分析系列七 进程管理 (3)

本文记录下进程相关的初始化函数,如OsSystemProcessCreate、OsProcessInit、OsProcessCreateInit、OsUserInitProcess、OsDeInitPCB、OsUserInitProcessStart等。

1、LiteOS-A内核进程创建初始化通用函数

先看看一些内部函数,不管是初始化用户态进程还是内核态进程,都会使用这些函数,包含进程控制块初始化函数OsInitPCB、进程控制块初始化恢复函数OsDeInitPCB

1.1 进程控制块初始化函数OsInitPCB

进程控制块初始化函数OsInitPCB需要3个参数,第一个参数processCB是进程块指针,第二个参数为进程模式mode,分为内核态进程OS_KERNEL_MODE和用户态进程OS_USER_MODE。第三个参数用于设置进程名称。返回值为初始化成功LOS_OK还是失败LOS_ENOMEM。看下代码,⑴处设置进程控制块的信息,用户态进程还是内核态进程,进程状态设置为初始化状态,线程组编号设置为无效值,设置为默认掩码,定时器编号设置为无效值。⑵处初始化进程的双向链表。如果系统配置支持虚拟内存,则执行⑶判断初始化的进程是否为用户态进程,如果是用户态进程,则创建虚拟地址空间,如果创建失败,则把进程状态设置为未使用状态,然后返回错误码。⑷处表示如果是内核态进程,则指定进程的内核进程虚拟地址空间。有关虚拟地址空间的信息,请参考之前的系列文章。

如果执行CPUP特性,则执行⑸处代码,则为CPUP结构体申请内存空间。⑹处,如果开启了LOSCFG_SECURITY_VID,则V初始化ID映射链表。⑺处,如果开启了安全能力LOSCFG_SECURITY_CAPABILITY,则进行相应的初始化。⑻处为进程设置一个名称。

    STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name){
⑴      processCB->processMode = mode;processCB->processStatus = OS_PROCESS_STATUS_INIT;processCB->parentProcessID = OS_INVALID_VALUE;processCB->threadGroupID = OS_INVALID_VALUE;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_KERNEL_CPUP
⑸      processCB->processCpup = (OsCpupBase *)LOS_MemAlloc(m_aucSysMem1, sizeof(OsCpupBase));if (processCB->processCpup == NULL) {return LOS_ENOMEM;}(VOID)memset_s(processCB->processCpup, sizeof(OsCpupBase), 0, sizeof(OsCpupBase));#endif#ifdef LOSCFG_SECURITY_VID
⑹      status_t status = VidMapListInit(processCB);if (status != LOS_OK) {return LOS_ENOMEM;}#endif⑺  #ifdef LOSCFG_SECURITY_CAPABILITYOsInitCapability(processCB);#endif⑻      if (OsSetProcessName(processCB, name) != LOS_OK) {return LOS_ENOMEM;}return LOS_OK;}

1.2 进程控制块初始化恢复函数OsDeInitPCB

在创建进程时,会执行该函数,恢复进程控制块信息到初始化之前的状态。⑴处释放进程的资源,包含地址空间、文件、安全能力、定时器等占用的内存。如果存在父进程,则执行⑵从父进程的兄弟列表上删除。如果进程属于进程组,则从进程组中退出。然后执行⑷设置进程状态为退出态,把进程放入待回收链表中。

    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;}

2、 LiteOS-A内核系统进程创建函数OsSystemProcessCreate

系统进程创建函数OsSystemProcessCreate在文件kernel\common\los_config.c中被调用,在系统启动阶段创建系统进程。该函数又调用OsProcessInit,我们首先看下函数OsProcessInit。

2.1 进程初始化函数OsProcessInit

进程初始化函数OsProcessInit为进程控制块申请内存,初始化进程相关的进程链表。我们看下代码,⑴处获取配置的进程最大数值,然后计算需要的内存大小。⑵处申请内存,初始化申请的内存块。⑶处初始化空闲进程双向链表和待回收进程双向链表。
⑷处初始化每一个进程,社区进程编号、进程状态,然后把每一个进程放到空闲进程链表里。⑸处设置Idle进程编号为0,用户根进程编号为1,系统根进程编号为2,然后执行LOS_ListDelete把这3个进程从阻塞链表上删除。

    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;}

2.2 进程创建初始化函数OsProcessCreateInit

该函数用于创建进程时的一些初始化操作,主要是文件系统、安全能力、进程组等等。需要3个参数,分别是进程控制块指针,标记用户态还是内核态进程的flags,进程名称name。首先执行⑴调用OsInitPCB()对进程控制块进行初始化,然后,如果配置支持了虚拟文件系统VFS,则执行⑵为进程分别文件。⑶处根据进程号创建进程组。如果支持安全能力,则执行⑷创建用户。如果初始化失败,会执行⑸恢复进程控制块到初始化之前的状态。

    STATIC UINT32 OsProcessCreateInit(LosProcessCB *processCB, UINT32 flags, const CHAR *name){ProcessGroup *group = NULL;
⑴      UINT32 ret = OsInitPCB(processCB, flags, name);if (ret != LOS_OK) {goto EXIT;}#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;}#endifreturn LOS_OK;EXIT:
⑸      OsDeInitPCB(processCB);return ret;}

2.3 系统进程创建函数OsSystemProcessCreate

接下来,我们看看系统进程创建函数OsSystemProcessCreate的源代码。⑴处开始先后调用OsProcessInit、OsProcessCreateInit初始化内核态根进程,⑵处进程的状态不再是初始化状态。⑶处从内核进程获取全局进程组指针g_processGroup,然后初始化进程组的双向链表。这样看来,所有的进程组都会挂载到内核进程的进程组节点上。⑷处初始化内核空闲进程,内核空闲进程的父进程也是内核态根进程,插入到进程组链表,设置空闲进程的状态不再是初始化状态。执行⑸创建空闲任务,然后设置空闲进程的线程组编号为空闲线程编号。

    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");if (ret != LOS_OK) {return ret;}⑵      kerInitProcess->processStatus &= ~OS_PROCESS_STATUS_INIT;
⑶      g_processGroup = kerInitProcess->group;LOS_ListInit(&g_processGroup->groupList);⑷      LosProcessCB *idleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess);ret = OsInitPCB(idleProcess, OS_KERNEL_MODE, "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_CAPABILITYidleProcess->user = kerInitProcess->user;#endif#ifdef LOSCFG_FS_VFSidleProcess->files = kerInitProcess->files;#endifidleProcess->processStatus &= ~OS_PROCESS_STATUS_INIT;⑸      ret = OsIdleTaskCreate();if (ret != LOS_OK) {return ret;}idleProcess->threadGroupID = OsGetIdleTaskId();return LOS_OK;}

3. LiteOS-A内核用户进程创建函数OsUserInitProcess

系统启动阶段,OsUserInitProcess启动init进程。该函数在device开发板目录下系统初始化文件中调用,如system_init.c等等。该函数需要开启LOSCFG_KERNEL_DYNLOAD宏,否则函数体内容为空。在阅读函数OsUserInitProcess的源码前,先看看该函数调用的其他函数,如OsLoadUserInit、OsUserInitStackAlloc、OsUserInitProcessStart等等。

3.1 加载用户初始化数据函数OsLoadUserInit

该函数用于加载用户数据。⑴处从链接脚本获取text、bss的开启和结束地址,然后计算bss段、初始化段的大小。⑵处进行一些必要的校验,是否针对内存页对齐,内存段长度是否合理等。然后执行⑶,申请物理内存页,然后把用户初始化数据复制到申请的内存页。⑷处进行虚实映射。如果bss段长度不为0,执行⑸把bss段的内存区域清零。

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;
}

3.2 用户初始化栈函数OsUserInitStackAlloc

该函数需要2个参数,第一个参数为进程控制块,第二个参数为输出参数,用于获取用户任务栈的大小。⑴处用户任务栈大小对页进行对齐,然后申请内存区域,然后执行⑵设置内存区域类型,并社区内存区域标签为栈。然后设置输出参数为任务栈大小,并返回用户栈空间的开始地址。

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;
}

3.3 用户进程初始化开启函数OsUserInitProcessStart

用户进程初始化开启函数OsUserInitProcessStart用于创建线程,设置调度策略等。⑴处为用户态进程创建个线程,然后为进程设置优先级。⑵处设置进程状态为非初始化状态,然后执行⑶为任务设置调度策略和优先级。

STATIC UINT32 OsUserInitProcessStart(LosProcessCB *processCB, TSK_INIT_PARAM_S *param)
{UINT32 intSave;INT32 ret;⑴  UINT32 taskID = OsCreateUserTask(processCB->processID, param);if (taskID == OS_INVALID_VALUE) {return LOS_NOK;}ret = LOS_SetProcessPriority(processCB->processID, OS_PROCESS_USERINIT_PRIORITY);if (ret != LOS_OK) {PRINT_ERR("User init process set priority failed! ERROR:%d \n", ret);goto EXIT;}SCHEDULER_LOCK(intSave);
⑵  processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;SCHEDULER_UNLOCK(intSave);⑶  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);goto EXIT;}return LOS_OK;EXIT:(VOID)LOS_TaskDelete(taskID);return ret;
}

3.4 用户态进程初始化函数OsUserInitProcess

用户态进程初始化函数OsUserInitProcess完成用户态进程的初始化。⑴处获取用户态根进程,然后调用函数创建用户态根进程,并调用函数OsLoadUserInit加载用户初始化数据。⑵处初始化用户栈,然后设置线程的初始化参数,⑶处完成用户态进程的创建。

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");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(processCB, &param);if (ret != LOS_OK) {(VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);goto ERROR;}return LOS_OK;ERROR:OsDeInitPCB(processCB);return ret;
}

小结

本文介绍了进程管理的内核进程、用户态进程的初始化相关函数。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com