提交 3231b208 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析
上级 d393a8b2
......@@ -11,15 +11,15 @@
* ### **致敬鸿蒙内核开发者**
感谢开放原子开源基金会,鸿蒙内核开发者提供了如此优秀的源码,让笔者一了多年的夙愿,津津乐道与此.越深入精读内核源码,越能感受到设计者的精巧用心,创新突破. 向开发者致敬ppp. 可以毫不夸张的说 kernel_liteos_a 可作为大学C语言,数据结构,操作系统,汇编语言 四门课程的教学项目.如此宝库,不深入研究真会觉得太可惜了.
感谢开放原子开源基金会,鸿蒙内核开发者提供了如此优秀的源码,让笔者一了多年的夙愿,津津乐道于此.越深入精读内核源码,越能感受到设计者的精巧用心,创新突破. 向开发者致敬ppp. 可以毫不夸张的说 kernel_liteos_a 可作为大学C语言,数据结构,操作系统,汇编语言 四门课程的教学项目.如此宝库,不深入研究实在是太可惜了.
* ### **系列篇和源码注释怎么更新**
好记性不如烂笔头,笔者把研究过程心得写成鸿蒙源码分析系列篇,如此源码注释结合系列篇文章理解鸿蒙内核实现会更彻底.
系列篇文章查看: 进入>> 鸿蒙源码分析系列篇 [CSDN站](https://blog.csdn.net/kuangyufei) | [oschina站](https://my.oschina.net/u/3751245) 查看, 正在持续更新中..., 感谢CSDN, oschina 对博文的推荐.
系列篇文章查看: 进入>> 鸿蒙源码分析系列篇 [CSDN站](https://blog.csdn.net/kuangyufei) | [OSCHINA站](https://my.oschina.net/u/3751245) 查看, 正在持续更新中..., 感谢CSDN, OSCHINA 对博文的推荐.
注释中文版查看: 进入>> 鸿蒙内核源码注释中文版 [CSDN仓库](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Gitee仓库 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [Github仓库](https://github.com/kuangyufei/kernel_liteos_a_note) 查看,三大仓库同步更新. 正在持续加注中....
注释中文版查看: 进入>> 鸿蒙内核源码注释中文版 [CSDN仓库](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Gitee仓库 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [Github仓库](https://github.com/kuangyufei/kernel_liteos_a_note) [coding仓库](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 查看,四大仓库同步更新. 正在持续加注中....
精读内核源码当然是件很困难的事,但正因为很难才值得去做! 内心不渴望的永远不可能靠近自己.别再去纠结而没有行动.笔者一直坚信兴趣是最好的老师,加注就是在做自己感兴趣的事, 希望感兴趣的各位能看到.如果能让更多人参与到内核的研究,减少学习的成本,哪怕就节省一天的时间,这么多人能节省多少时间, 这是件多好玩,多有意义的事情啊.
......
......@@ -498,66 +498,66 @@ STATIC VOID OsProcessNaturalExit(LosTaskCB *runTask, UINT32 status)
LOS_Panic("pid : %u is the root process exit!\n", processCB->processID);
return;
}
LITE_OS_SEC_TEXT_INIT UINT32 OsProcessInit(VOID)//进程模块初始化
//进程模块初始化,被编译放在代码段 .init 中
LITE_OS_SEC_TEXT_INIT UINT32 OsProcessInit(VOID)
{
UINT32 index;
UINT32 size;
g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT;// 默认是64个
size = g_processMaxNum * sizeof(LosProcessCB);
g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT;//默认支持64个进程
size = g_processMaxNum * sizeof(LosProcessCB);//算出总大小
g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);// 进程池,占用内核堆
g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);// 进程池,占用内核堆,内存池分配
if (g_processCBArray == NULL) {
return LOS_NOK;
}
(VOID)memset_s(g_processCBArray, size, 0, size);//安全方式重置
(VOID)memset_s(g_processCBArray, size, 0, size);//安全方式重置清0
LOS_ListInit(&g_freeProcess);//进程空闲链表初始化,创建一个进程时从g_freeProcess中申请一个进程描述符使用
LOS_ListInit(&g_processRecyleList);//进程回收链表初始化,回收完成后进入g_freeProcess等待再次被申请使用
for (index = 0; index < g_processMaxNum; index++) {
for (index = 0; index < g_processMaxNum; index++) {//进程池循环创建
g_processCBArray[index].processID = index;//进程ID[0-g_processMaxNum]赋值
g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;// 默认都是白纸一张,臣妾干净着呢
LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList);// 初始全是可分配进程描述符
}
g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 */
// ????? 为啥用户模式的根进程 选1 ,内核模式的根进程选2
g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 *///用户模式的根进程
LOS_ListDelete(&g_processCBArray[g_userInitProcess].pendList);// 清空g_userInitProcess pend链表
g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 */
g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 *///内核模式的根进程
LOS_ListDelete(&g_processCBArray[g_kernelInitProcess].pendList);// 清空g_kernelInitProcess pend链表
return LOS_OK;
}
//创建一个名叫"KIdle"的进程,给CPU空闲的时候使用
STATIC UINT32 OsCreateIdleProcess(VOID)
{
UINT32 ret;
CHAR *idleName = "Idle";
LosProcessCB *idleProcess = NULL;
Percpu *perCpu = OsPercpuGet();
UINT32 *idleTaskID = &perCpu->idleTaskID;
UINT32 *idleTaskID = &perCpu->idleTaskID;//得到CPU的idle task
ret = OsCreateResourceFreeTask();// 创建一个资源回收任务
ret = OsCreateResourceFreeTask();// 创建一个资源回收任务,优先级为5 用于回收进程退出时的各种资源
if (ret != LOS_OK) {
return ret;
}
//创建一个名叫"KIdle"的进程,并创建一个idle task,CPU空闲的时候就待在 idle task中等待被唤醒
ret = LOS_Fork(CLONE_FILES, "KIdle", (TSK_ENTRY_FUNC)OsIdleTask, LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE);
if (ret < 0) {
return LOS_NOK;
}
g_kernelIdleProcess = (UINT32)ret;
g_kernelIdleProcess = (UINT32)ret;//返回进程ID
idleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess);
*idleTaskID = idleProcess->threadGroupID;
OS_TCB_FROM_TID(*idleTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;
idleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess);//通过ID拿到进程实体
*idleTaskID = idleProcess->threadGroupID;//绑定CPU的IdleTask,或者说改变CPU现有的idle任务
OS_TCB_FROM_TID(*idleTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//设定Idle task 为一个系统任务
#if (LOSCFG_KERNEL_SMP == YES)
OS_TCB_FROM_TID(*idleTaskID)->cpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
OS_TCB_FROM_TID(*idleTaskID)->cpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());//多核CPU的任务指定,防止乱串了,注意多核才会有并行处理
#endif
(VOID)memset_s(OS_TCB_FROM_TID(*idleTaskID)->taskName, OS_TCB_NAME_LEN, 0, OS_TCB_NAME_LEN);
(VOID)memcpy_s(OS_TCB_FROM_TID(*idleTaskID)->taskName, OS_TCB_NAME_LEN, idleName, strlen(idleName));
(VOID)memset_s(OS_TCB_FROM_TID(*idleTaskID)->taskName, OS_TCB_NAME_LEN, 0, OS_TCB_NAME_LEN);//task 名字先清0
(VOID)memcpy_s(OS_TCB_FROM_TID(*idleTaskID)->taskName, OS_TCB_NAME_LEN, idleName, strlen(idleName));//task 名字叫 idle
return LOS_OK;
}
......
......@@ -124,10 +124,10 @@ VOID OsSetMainTask()
LOS_ListInit(&g_mainTask[i].lockList);//初始化 每个CPU core 持有的锁链表
}
}
LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID)//空任务
//空闲任务 注意 #define WEAK __attribute__((weak)) 是用于防止crash的
LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID)
{
while (1) {
while (1) {//只有一个死循环
#ifdef LOSCFG_KERNEL_TICKLESS
if (OsTickIrqFlagGet()) {
OsTickIrqFlagSet(0);
......@@ -243,7 +243,7 @@ LITE_OS_SEC_TEXT UINT32 OsTaskSetDeatchUnsafe(LosTaskCB *taskCB)
return LOS_EINVAL;
}
//任务扫描
LITE_OS_SEC_TEXT VOID OsTaskScan(VOID)
{
SortLinkList *sortList = NULL;
......@@ -253,7 +253,7 @@ LITE_OS_SEC_TEXT VOID OsTaskScan(VOID)
LOS_DL_LIST *listObject = NULL;
SortLinkAttribute *taskSortLink = NULL;
taskSortLink = &OsPercpuGet()->taskSortLink;
taskSortLink = &OsPercpuGet()->taskSortLink;//获取任务的排序链表
taskSortLink->cursor = (taskSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
listObject = taskSortLink->sortLink + taskSortLink->cursor;
......@@ -841,7 +841,7 @@ LOS_ERREND_REWIND_TCB:
LOS_ERREND:
return errRet;
}
//创建Task
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
UINT32 ret;
......@@ -856,35 +856,35 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *in
return LOS_ERRNO_TSK_YIELD_IN_INT;
}
if (initParam->uwResved & OS_TASK_FLAG_IDLEFLAG) {
initParam->processID = OsGetIdleProcessID();
} else if (OsProcessIsUserMode(OsCurrProcessGet())) {
initParam->processID = OsGetKernelInitProcessID();
if (initParam->uwResved & OS_TASK_FLAG_IDLEFLAG) {//OS_TASK_FLAG_IDLEFLAG 是属于内核 idle进程专用的
initParam->processID = OsGetIdleProcessID();//获取空闲进程
} else if (OsProcessIsUserMode(OsCurrProcessGet())) {//当前进程是否为用户模式
initParam->processID = OsGetKernelInitProcessID();//不是就取"Kernel"进程
} else {
initParam->processID = OsCurrProcessGet()->processID;
initParam->processID = OsCurrProcessGet()->processID;//获取当前进程 ID赋值
}
initParam->uwResved &= ~OS_TASK_FLAG_IDLEFLAG;
initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN;
if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) {
initParam->uwResved = OS_TASK_FLAG_DETACHED;
initParam->uwResved &= ~OS_TASK_FLAG_IDLEFLAG;//不能是 OS_TASK_FLAG_IDLEFLAG
initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN;//不能是 OS_TASK_FLAG_PTHREAD_JOIN
if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) {//是否设置了自动删除
initParam->uwResved = OS_TASK_FLAG_DETACHED;//自动删除,注意这里是 = ,也就是说只有 OS_TASK_FLAG_DETACHED 一个标签了
}
ret = LOS_TaskCreateOnly(taskID, initParam);
ret = LOS_TaskCreateOnly(taskID, initParam);//创建一个任务,这是任务创建的实体,前面都只是前期准备工作
if (ret != LOS_OK) {
return ret;
}
taskCB = OS_TCB_FROM_TID(*taskID);
taskCB = OS_TCB_FROM_TID(*taskID);//通过ID拿到task实体
SCHEDULER_LOCK(intSave);
taskCB->taskStatus &= ~OS_TASK_STATUS_INIT;
OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, 0);
taskCB->taskStatus &= ~OS_TASK_STATUS_INIT;//任务不再是初始化
OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, 0);//进入调度就绪队列,新任务是直接进入就绪队列的
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();
LOS_MpSchedule(OS_MP_CPU_ALL);//如果创建的任务没有在这个核心上运行,是否调度取决于其他调度程序的状态。
if (OS_SCHEDULER_ACTIVE) {//当前CPU核处于可调度状态
LOS_Schedule();//发起调度
}
return LOS_OK;
......
......@@ -82,7 +82,7 @@ STATIC VOID OsSchedSwitchProcess(LosProcessCB *runProcess, LosProcessCB *newProc
newProcess->timeSlice = OS_PROCESS_SCHED_RR_INTERVAL;//重新分配时间片,默认 20ms
}
}
//重新调度实现
VOID OsSchedResched(VOID)
{
LosTaskCB *runTask = NULL;
......@@ -90,50 +90,50 @@ VOID OsSchedResched(VOID)
LosProcessCB *runProcess = NULL;
LosProcessCB *newProcess = NULL;
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//必须持有任务自旋锁,自旋锁是不是进程层面去抢锁,而是CPU各自核之间去争夺锁
if (!OsPreemptableInSched()) {
if (!OsPreemptableInSched()) {//是否置了重新调度标识位
return;
}
runTask = OsCurrTaskGet();
newTask = OsGetTopTask();
runTask = OsCurrTaskGet();//获取当前任务
newTask = OsGetTopTask();//获取优先级最最最高的任务
/* always be able to get one task */
LOS_ASSERT(newTask != NULL);
LOS_ASSERT(newTask != NULL);//不能没有需调度的任务
if (runTask == newTask) {
if (runTask == newTask) {//当前任务就是最高任务,那还调度个啥的,直接退出.
return;
}
runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;//当前任务状态位置成不在运行状态
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//最高任务状态位置成在运行状态
runProcess = OS_PCB_FROM_PID(runTask->processID);
newProcess = OS_PCB_FROM_PID(newTask->processID);
runProcess = OS_PCB_FROM_PID(runTask->processID);//通过进程ID索引拿到进程实体
newProcess = OS_PCB_FROM_PID(newTask->processID);//同上
OsSchedSwitchProcess(runProcess, newProcess);
OsSchedSwitchProcess(runProcess, newProcess);//切换进程,里面主要涉及进程空间的切换,也就是MMU的上下文切换.
#if (LOSCFG_KERNEL_SMP == YES)
#if (LOSCFG_KERNEL_SMP == YES)//CPU多核的情况
/* mask new running task's owner processor */
runTask->currCpu = OS_TASK_INVALID_CPUID;
newTask->currCpu = ArchCurrCpuid();
runTask->currCpu = OS_TASK_INVALID_CPUID;//当前任务不占用CPU
newTask->currCpu = ArchCurrCpuid();//让新任务占用CPU
#endif
(VOID)OsTaskSwitchCheck(runTask, newTask);
(VOID)OsTaskSwitchCheck(runTask, newTask);//切换task的检查
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
OsSchedStatistics(runTask, newTask);
#endif
if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {
newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;
if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {//没有时间片且是抢占式调度的方式,注意 非抢占式都不需要时间片的.
newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;//给新任务时间片 默认 20ms
}
OsCurrTaskSet((VOID*)newTask);
OsCurrTaskSet((VOID*)newTask);//设置新的task为CPU核的当前任务
if (OsProcessIsUserMode(newProcess)) {
OsCurrUserTaskSet(newTask->userArea);
if (OsProcessIsUserMode(newProcess)) {//用户模式下会怎么样?
OsCurrUserTaskSet(newTask->userArea);//设置task栈空间
}
PRINT_TRACE("cpu%d run process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x ->\n"
......@@ -145,7 +145,7 @@ VOID OsSchedResched(VOID)
newProcess->threadScheduleMap, newTask->taskName, newTask->taskID, newTask->taskStatus);
/* do the task context switch */
OsTaskSchedule(newTask, runTask);
OsTaskSchedule(newTask, runTask);//再执行调度,主要是切换CPU的上下文
}
VOID OsSchedPreempt(VOID)
......
......@@ -491,7 +491,7 @@ typedef struct {
*
* Information of specified parameters passed in during task creation.
*/
typedef struct tagTskInitParam {
typedef struct tagTskInitParam {//Task的初始化参数
TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function */
UINT16 usTaskPrio; /**< Task priority */
UINT16 policy; /**< Task policy */
......
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 打印机
void printer(char *str)
{
while(*str!='\0')
{
putchar(*str);
fflush(stdout);
str++;
sleep(1);
}
printf("\n");
}
// 线程一
void *thread_fun_1(void *arg)
{
char *str = "hello";
printer(str); //打印
}
// 线程二
void *thread_fun_2(void *arg)
{
char *str = "world";
printer(str); //打印
}
int main(void)
{
pthread_t tid1, tid2;
// 创建 2 个线程
pthread_create(&tid1, NULL, thread_fun_1, NULL);
pthread_create(&tid2, NULL, thread_fun_2, NULL);
// 等待线程结束,回收其资源
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册