当前位置: 首页 > 科技观察

鸿蒙LightKernelA核心源码解析系列之7—进程管理

时间:2023-03-19 15:32:42 科技观察

更多内容请访问:鸿蒙技术社区,与华为官方共建https://ost.51cto。com本文继续分析OpenHarmonyLiteOS-A内核的源码,然后分析进程和任务管理模块。本文涉及的源代码以OpenHarmonyLiteOS-A内核为例,可在开源站点https://gitee.com/openharmony/kernel_liteos_a获取。如果涉及到开发板,默认以hispark_taurus为例。本文首先熟悉进程管理的概念、运行机制和编程接口。一、LiteOS-A内核进程的基本概念进程是系统资源管理的最小单位。OpenHarmonyLiteOS-A内核提供的进程模块主要用于实现用户态进程的隔离。内核态被认为是一个进程空间,没有其他进程(除了KIdle,它是系统提供的空闲进程,与KProcess共享一个进程空间)。1.1LiteOS-A内核进程特点LiteOS-A内核进程具有以下特点:进程模块主要为用户提供多个进程,实现进程之间的切换和通信,帮助用户管理业务程序进程。进程采用抢占式调度机制,采用高优先级优先级+同优先级时间片轮换的调度算法。进程共有32个优先级(0-31),用户进程可以配置22个优先级(10-31),最高优先级为10,最低优先级为31。高优先级进程可以抢占低优先级进程-优先级进程,低优先级进程必须在高优先级进程被调度之前被阻塞或终止。每个用户态进程都有自己独立的进程空间,相互不可见,实现了进程间的隔离。用户态根进程init由内核态创建,其他用户态子进程从init进程fork出来。1.2LiteOS-A内核进程状态LiteOS-A内核进程状态包括初始化态、就绪态、运行态、阻塞态、死态等几种状态。初始化(Init):正在创建进程。就绪:进程在就绪列表中,等待CPU调度。正在运行:进程正在运行。阻塞(Pending):进程被阻塞并挂起。当这个进程中的所有线程都被阻塞时,进程就被阻塞挂起。Zombies:进程结束运行,等待父进程回收其控制块资源。各状态转换示意图如下,图片来自openharmonydocs文档仓库:进程状态转换解释如下:1.Init→Ready:进程创建或fork后,进入Init状态获取进程控制块,处于进程初始化阶段。进程初始化完成后,进程被插入到调度队列中,进程进入就绪状态。2.Ready→Running:进程创建后,进入就绪状态。当发生进程切换时,就绪列表中优先级最高的进程被执行,从而进入运行状态。如果此时进程中没有其他线程处于就绪状态,则将该进程从就绪列表中删除,仅处于运行状态;如果此时进程中还有其他线程处于就绪状态,则该进程还在就绪队列中。进程的就绪状态和运行状态并存,但对外呈现的进程状态是运行状态。3、Running→Pending:当进程的最后一个线程处于阻塞状态时,进程中的所有线程都处于阻塞状态。此时进程同步进入阻塞状态,然后发生进程切换。4.Pending→Ready:当阻塞进程中的任意线程返回就绪状态时,该进程被加入就绪队列,同步变为就绪状态。5.Ready→Pending:当进程中最后一个处于就绪态的线程变为阻塞态时,进程从就绪链表中删除,进程由就绪态变为阻塞态。6.Running→Ready:进程从运行状态变为就绪状态有两种情况:6.1优先级更高的进程创建或恢复后,会发生进程调度,此时优先级最高的进程在就绪列表中变为运行状态,之前运行的进程从运行状态变为就绪状态。6.2如果一个进程的调度策略为LOS_SCHED_RR,而另一个具有相同优先级的进程处于就绪态,则在该进程的时间片耗尽后,该进程将从运行态变为就绪态,另一个进程具有相同优先级的将处于就绪状态。就绪状态变为运行状态。7.Running→Zombies:当主线程或进程的所有线程运行完毕后,进程由运行状态变为僵尸状态,等待父进程回收资源。2.LiteOS-A内核进程运行机制OpenHarmony提供的进程模块主要用于实现用户态进程的隔离,支持创建、退出、资源回收、设置/获取调度参数、获取进程ID、设置/用户态进程获取进程GroupID等功能。用户态进程来自fork父进程。当fork进程将父进程的进程虚拟内存空间克隆到子进程时,子进程通过copy-on-write机制按需将父进程的内容复制到子进程的虚拟内存空间进程实际上正在运行。内存空间。进程只是一个资源管理单元,实际操作是由进程中的各个线程完成的。当不同进程中的线程相互切换时,进程空间也会发生切换。3.LiteOS-A内核进程模块接口3.1LiteOS-A内核进程模块对外接口进程模块对外接口文件kernel\include\los_process.h定义了接口,如下表所示。完整的接口声明如下:externINT32LOS_Fork(UINT32flags,constCHAR*name,constTSK_ENTRY_FUNCentry,UINT32stackSize);externINT32LOS_SetProcessPriority(INT32pid,UINT16prio);externINT32LOS_GetProcessPriority(INT32pid2);externINT32LOS_GetProcessPriority(INT32pid2GetProcessINT3INT2);pid);externINT32LOS_SetProcessScheduler(INT32pid,UINT16policy,UINT16prio);externUINT32LOS_GetCurrProcessID(VOID);externINT32LOS_Wait(INT32pid,USERINT32*status,UINT32options,VOID*usage);externINT32LOS_Waitid(INT32pid,USERsiginfo_t*info,UINT32options,VOID*usage);externINT32LOS_GetCurrProcessGroupID(VOID);externINT32LOS_GetProcessGroupID(UINT32pid);externVOIDLOS_Exit(INT32status);externUINT32LOS_GetSystemProcessMaximum(VOID);#ifdefLOSCFG_SECURITY_CAPABILITYCheckInternBOOLGroupsUINT32gid);#endifexternINT32LOS_GetUserID(VOID);externINT32LOS_GetGroupID(VOID);externINT32LOS_GetUsedPIDList(UINT32*pidList,INT32pidMaxNum);#ifdefLOSCFG_FS_VFstructfd_table_s*LOS_GetFdTable(UINT32pid);#endif3.2LiteOS-A内核进程模块结构私有头文件kernel\base\include\los_process_pri.h定义宏、结构体等进程组和进程控制块结构如下。对于一个进程组,如(1)所示,进程组的编号等于创建该进程组的进程的进程号。每个进程组维护一个链表挂载本组的非僵尸进程,也维护一个链表挂载本组的僵尸进程。所有进程通过链表节点groupList挂载到全局进程组链表上,可以方便进程组的管理。进程控制块的结构比较复杂,⑵-⑶维护进程名、ID号、状态、模式、退出状态等,⑷-⑷维护各种链表、进程组信息、线程数等。接下来维护多核CPU信息、信号信息、虚拟地址帧、文件、安全能力等,具体到代码的时候,深入分析这些结构体成员。typedefstruct{⑴UINT32groupID;/**<进程组ID是创建该组的进程的PID*/LOS_DL_LISTprocessList;/**<该进程组下的进程列表*/LOS_DL_LISTexitProcessList;/**<该组下关闭的进程(僵尸进程)列表*/LOS_DL_LISTgroupList;/**<进程组列表*/}ProcessGroup;typedefstructProcessCB{⑵CHAR进程名[OS_PCB_NAME_LEN];/**<进程名*/UINT32processID;/**<进程ID*/UINT16processStatus;/**<[15:4]进程状态;[3:0]进程当前运行的线程数*/UINT16consoleID;/**<任务所属控制台id*/UINT16processM颂;/**<内核模式:0;用户模式:1;*/UINT32parentProcessID;/**<父进程ID*/⑶UINT32exitCode;/**<进程退出状态*/⑷LOS_DL_LISTpendList;/**<进程所属的块列表*/LOS_DL_LISTchildrenList;/**<子进程列表*/LOS_DL_LISTexitChildList;/**<退出子进程列表*/LOS_DL_LISTsiblingList;/**<父子列表中的链接*/ProcessGroup*group;/**<进程所属的进程组*/LOS_DL_LISTsubordinateGroupList;/**<组列表中的链接*/UINT32threadGroupID;/**<哪个线程组,是进程的主线程ID*/LOS_DL_LISTthreadSiblingList;/**<该进程下的线程列表*/volatileUINT32threadNumber;/**<该进程下存活的线程数*/UINT32threadCount;/**<本进程下创建的线程总数*/⑸LOS_DL_LISTwaitList;/**<进程持有waitLits以支持wait/waitpid*/#ifdefLOSCFG_KERNEL_SMPUINT32timerCpu;/**<该任务的CPU核心数被延迟或挂起*/#endifUINTPTRsigHandler;/**<信号处理程序*/sigset_tsigShare;/**<信号共享位*/#ifdefLOSCFG_KERNEL_LITEIPCProcIpcInfo*ipcInfo;/**processStatus&OS_PROCESS_FLAG_UNUSED)!=0);}STATICINLINEBOOLOsProcessIsInactive(constLosProcessCB*processCB){return((processCB->processStatus&(OS_PROCESS_FLAG_ACTUSED|OS_PROCESS_STATUS)))!=0);}STATICINLINEBOOLOsProcessIsDead(constLosProcessCB*processCB){return((processCB->processStatus&(OS_PROCESS_FLAG_UNUSED|OS_PROCESS_STATUS_ZOMBIES))!=0);}STATICINLINEBOOLOsProcessIsInit(constLosProcessCB*processCB){return(processCB->processStatus&OS_PROCESS_STATUS_INIT);}STATICINLINEBOOLOsProcessIsUserMode(constLosProcessCB*processCB){return(processCB->processMode==OS_USER_MODE);}下面描述几个对指定程序设置不同的退出代码、退出代码信号等。/**进程退出代码*3115870*||退出代码|核心转储|信号|*/#defineOS_PRO_EXIT_OK0STATICINLINEVOIDOsProcessExitCodeCoreDumpSet(LosProcessCB*processCB){processCB->exitCode|=0x80U;}STATICINLINEVOIDOsProcessExitCodeSignalSet(LosProcessCB*processCB,UINT32信号){processCB->exitCode|=信号&0x7LINEFU;}STATICINLINEFUVOIDOsProcessExitCodeSignalClear(LosProcessCB*processCB){processCB->exitCode&=(~0x7FU);}静态内联BOOLOsProcessExitCodeSignalIsSet(LosProcessCB*processCB){return(processCB->exitCode)&0x7FU;}STATICINLINEVOIDOsProcessExitCodeSet(LosProcess,CB*processUINT32代码){processCB->exitCode|=((代码&0x000000FFU)<<8U)&0x0000FF00U;/*8:向左移动8位,exitCode*/}参考站点OpenHarmony/docs进程管理kernel_liteos_alos_process.hkernel_liteos_alos_process.kernel_liteos_alos_process_pri.h小结本介绍了进程管理的概念、运行机制和编程接口更多信息请访问:与华为官方共同建立的鸿蒙技术社区https://ost.51cto.com