天天看點

v46.05 鴻蒙核心源碼分析(特殊程序篇) | 龍生龍,鳳生鳳,老鼠生兒會打洞 | 百篇部落格分析OpenHarmony源碼

寝不屍,居不容。見齊衰者,雖狎,必變。見冕者與瞽者,雖亵,必以貌。兇服者式之。式負版者。有盛馔,必變色而作。迅雷風烈,必變 《論語》:鄉黨篇

v46.05 鴻蒙核心源碼分析(特殊程式篇) | 龍生龍,鳳生鳳,老鼠生兒會打洞 | 百篇部落格分析OpenHarmony源碼

百篇部落格系列篇.本篇為:

v46.xx 鴻蒙核心源碼分析(特殊程序篇) | 老鼠生兒會打洞

程序管理相關篇為:

  • v02.06 鴻蒙核心源碼分析(程序管理) | 誰在管理核心資源
  • v24.03 鴻蒙核心源碼分析(程序概念) | 程序在管理哪些資源
  • v45.05 鴻蒙核心源碼分析(Fork) | 一次調用,兩次傳回
  • v46.05 鴻蒙核心源碼分析(特殊程序) | 老鼠生兒會打洞
  • v47.02 鴻蒙核心源碼分析(程序回收) | 臨終前如何向老祖宗托孤
  • v48.05 鴻蒙核心源碼分析(信号生産) | 年過半百,依然活力十足
  • v49.03 鴻蒙核心源碼分析(信号消費) | 誰讓CPU連續四次換棧運作
  • v71.03 鴻蒙核心源碼分析(Shell編輯) | 兩個任務,三個階段
  • v72.01 鴻蒙核心源碼分析(Shell解析) | 應用窺伺核心的視窗

三個程序

鴻蒙有三個特殊的程序,建立順序如下:

  • 2号程序,

    KProcess

    ,為核心态根程序.啟動過程中建立.
  • 0号程序,

    KIdle

    為核心态第二個程序,它是通過

    KProcess

    fork 而來的.這有點難了解.
  • 1号程序,

    init

    ,為使用者态根程序.由任務

    SystemInit

    建立.
  • 發現沒有在圖中看不到0号程序,在看完本篇之後請想想為什麼?

家族式管理

  • 程序(process)是家族式管理,總體分為兩大家族,使用者态家族和核心态家族.
  • 使用者态的程序是平民階層,屌絲矮矬窮,幹着各行各業的活,權利有限,人數衆多,活動範圍有限(使用者空間).有關機關肯定不能随便進出.這個階層有個共同的老祖宗g_userInitProcess (1号程序).
    g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 *///使用者态的根程序
    //擷取使用者态程序的根程序,所有使用者程序都是g_processCBArray[g_userInitProcess] fork來的
    LITE_OS_SEC_TEXT UINT32 OsGetUserInitProcessID(VOID)
    {
        return g_userInitProcess;
    }
               
  • 核心态的程序是貴族階層,管理平民階層的,維持平民生活秩序的,擁有超級權限,能通路整個空間和所有資源,人數不多.這個階層老祖宗是 g_kernelInitProcess(2号程序).
    g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 *///核心态的根程序
    //擷取核心态程序的根程序,所有核心程序都是g_processCBArray[g_kernelInitProcess] fork來的,包括g_processCBArray[g_kernelIdleProcess]程序
    LITE_OS_SEC_TEXT UINT32 OsGetKernelInitProcessID(VOID)
    {
        return g_kernelInitProcess;
    }
               
  • 兩位老祖宗都不是通過fork來的,而是核心強制規定程序ID号,強制寫死基因建立的.
  • 這兩個階層可以互相流動嗎,有沒有可能通過聯考改變命運? 答案是: 絕對冇可能!!! 龍生龍,鳳生鳳,老鼠生兒會打洞.從老祖宗建立的那一刻起就被刻在基因裡了,抹不掉了. 因為後續所有的程序都是由這兩位老同志克隆(clone)來的,沒得商量的繼承這份基因.

    LosProcessCB

    有專門的标簽來

    processMode

    區分這兩個階層.整個鴻蒙核心源碼并沒有提供改變命運機會的

    set

    函數.
    #define OS_KERNEL_MODE 0x0U	//核心态
      #define OS_USER_MODE   0x1U	//使用者态
      STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)//使用者模式程序
      {
          return (processCB->processMode == OS_USER_MODE);
      }
      typedef struct ProcessCB {
          // ...
          UINT16               processMode;                  /**< Kernel Mode:0; User Mode:1; */	//0位核心态,1為使用者态程序
      } LosProcessCB;    
               

2号程序 KProcess

2号程序為核心态的老祖宗,是核心建立的首個程序,源碼過程如下,省略了不相幹的代碼.

bl     main  @帶LR的子程式跳轉, LR = pc - 4 ,執行C層main函數
/******************************************************************************
核心入口函數,由彙編調用,見于reset_vector_up.S 和 reset_vector_mp.S
up指單核CPU, mp指多核CPU bl        main
******************************************************************************/
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)//由主CPU執行,預設0号CPU 為主CPU 
{
    // ... 省略
    uwRet = OsMain();// 核心各子產品初始化
}
LITE_OS_SEC_TEXT_INIT INT32 OsMain(VOID)
{
    // ... 
    ret = OsKernelInitProcess();// 建立核心态根程序
    // ...
    ret = OsSystemInit(); //中間建立了使用者态根程序
}
//初始化 2号程序,即核心态程序的老祖宗
LITE_OS_SEC_TEXT_INIT UINT32 OsKernelInitProcess(VOID)
{
    LosProcessCB *processCB = NULL;
    UINT32 ret;

    ret = OsProcessInit();// 初始化程序子產品全部變量,建立各循環雙向連結清單
    if (ret != LOS_OK) {
        return ret;
    }

    processCB = OS_PCB_FROM_PID(g_kernelInitProcess);// 以PID方式得到一個程序
    ret = OsProcessCreateInit(processCB, OS_KERNEL_MODE, "KProcess", 0);// 初始化程序,最高優先級0,鴻蒙程序一共有32個優先級(0-31) 其中0-9級為核心程序,使用者程序可配置的優先級有22個(10-31)
    if (ret != LOS_OK) {
        return ret;
    }

    processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;// 程序初始化位 置1
    g_processGroup = processCB->group;//全局程序組指向了KProcess所在的程序組
    LOS_ListInit(&g_processGroup->groupList);// 程序組連結清單初始化
    OsCurrProcessSet(processCB);// 設定為目前程序
    return OsCreateIdleProcess();// 建立一個空閑狀态的程序
}
           

解讀

  • main函數在系列篇中會單獨講,請留意自行翻看,它是在開機之初在SVC模式下建立的.
  • 核心态老祖宗的名字叫

    KProcess

    ,優先級為最高 0 級,

    KProcess

    程序是長期活躍的,很多重要的任務都會跑在其之下.例如:
    • Swt_Task

    • oom_task

    • system_wq

    • tcpip_thread

    • SendToSer

    • SendToTelnet

    • eth_irq_task

    • TouchEventHandler

    • USB_GIANT_Task

      此處不細講這些任務,在其他篇幅有介紹,但光看名字也能猜個八九,請自行翻看.
  • 緊接着

    KProcess

    CLONE_FILES

    的方式 fork了一個 名為

    KIdle

    的子程序(0号程序).
  • 核心态的所有程序都來自2号程序這位老同志,子子孫孫,代代相傳,形成一顆家族樹,和人類的傳承所不同的是,它們往往是白發人送黑發人,子孫程序往往都是短命鬼,老祖宗最能活,子孫都死絕了它還在,有些收屍的工作要交給它幹.

0 号程序 KIdle

0号程序是核心建立的第二個程序,在

OsKernelInitProcess

的末尾将

KProcess

設為目前程序後,緊接着就

fork

了0号程序.為什麼一定要先設定目前程序,因為fork需要一個父程序,而此時系統處于啟動階段,并沒有目前程序. 是的,您沒有看錯.程序是作業系統為友善管理資源而衍生出來的概念,系統并不是非要程序,任務才能運作的. 開機階段就是啥都沒有,預設跑在svc模式下,預設起始位址

reset_vector

都是由硬體上電後規定的. 程序,線程都是跑起來後慢慢賦予的意義.

OsCurrProcessSet

是從軟體層面賦予了此為目前程序的這個概念.

KProcess

是核心設定的第一個目前程序.有了它,就可以fork, fork, fork !

//建立一個名叫"KIdle"的0号程序,給CPU空閑的時候使用
STATIC UINT32 OsCreateIdleProcess(VOID)
{
    UINT32 ret;
    CHAR *idleName = "Idle";
    LosProcessCB *idleProcess = NULL;
    Percpu *perCpu = OsPercpuGet();
    UINT32 *idleTaskID = &perCpu->idleTaskID;//得到CPU的idle task

    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) {//核心程序的fork并不會一次調用,傳回兩次,此子程序執行的開始位置是參數OsIdleTask
        return LOS_NOK;
    }
    g_kernelIdleProcess = (UINT32)ret;//傳回 0号程序

    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());//多核CPU的任務指定,防止亂串了,注意多核才會有并行處理
#endif
    (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;
}
           
  • 看過fork篇的可能發現了一個參數,

    KIdle

    被建立的方式和通過系統調用建立的方式不一樣,一個用的是

    CLONE_FILES

    ,一個是

    CLONE_SIGHAND

    具體的建立方式如下:
    #define CLONE_VM       0x00000100	//子程序與父程序運作于相同的記憶體空間
      #define CLONE_FS       0x00000200	//子程序與父程序共享相同的檔案系統,包括root、目前目錄、umask
      #define CLONE_FILES    0x00000400	//子程序與父程序共享相同的檔案描述符(file descriptor)表
      #define CLONE_SIGHAND  0x00000800	//子程序與父程序共享相同的信号處理(signal handler)表
      #define CLONE_PTRACE   0x00002000	//若父程序被trace,子程序也被trace
      #define CLONE_VFORK    0x00004000	//父程序被挂起,直至子程序釋放虛拟記憶體資源
      #define CLONE_PARENT   0x00008000	//建立的子程序的父程序是調用者的父程序,新程序與建立它的程序成了“兄弟”而不是“父子”
      #define CLONE_THREAD   0x00010000	//Linux 2.4中增加以支援POSIX線程标準,子程序與父程序共享相同的線程群
               
  • KIdle

    建立了一個名為

    Idle

    的任務,任務的入口函數為

    OsIdleTask

    ,這是個空閑任務,啥也不幹的.專門用來給cpu休息的,cpu空閑時就待在這個任務裡等活幹.
    LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID)
      {
          while (1) {//隻有一個死循環
      #ifdef LOSCFG_KERNEL_TICKLESS //低功耗模式開關, idle task 中關閉tick
              if (OsTickIrqFlagGet()) {
                  OsTickIrqFlagSet(0);
                  OsTicklessStart();
              }
      #endif
              Wfi();//WFI指令:arm core 立即進入low-power standby state,進入休眠模式,等待中斷.
          }
      }
               
  • fork 核心态程序和fork使用者态程序有個地方會不一樣,就是SP寄存器的值.fork使用者态的程序一次調用兩次傳回(父子程序各一次),傳回的位置一樣(是因為拷貝了父程序陷入核心時的上下文).是以可以通過傳回值來判斷是父還是子傳回.這個在fork篇中有詳細的描述.請自行翻看. 但fork核心态程序雖也有兩次傳回,但是傳回的位置卻不一樣,子程序的傳回位置是由核心指定的,例如:

    Idle

    任務的入口函數為

    OsIdleTask

    .詳見代碼:
    //任務初始化時拷貝任務資訊
      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();//擷取目前task,注意變量名從這裡也可以看出 thread 和 task 是一個概念,隻是核心常說task,上層應用說thread ,概念的映射.
    
          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 {//注意核心态程序建立任務的入口由外界指定,例如 OsCreateIdleProcess 指定了OsIdleTask
              childPara->pfnTaskEntry = (TSK_ENTRY_FUNC)entry;//參數(sp)為核心态入口位址
              childPara->uwStackSize = size;//參數(size)為核心态棧大小
          }
          childPara->pcName = (CHAR *)name;					//拷貝程序名字
          childPara->policy = mainThread->policy;				//拷貝排程模式
          childPara->usTaskPrio = mainThread->priority;		//拷貝優先級
          childPara->processID = childProcessCB->processID;	//拷貝程序ID
          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);
      }
               
  • 結論是建立0号程序中的

    OsCreateIdleProcess

    調用

    LOS_Fork

    後隻會有一次傳回.而且傳回值為0,因為

    g_freeProcess

    中0号程序還沒有被配置設定.詳見代碼,注意看最後的注釋:
    //程序子產品初始化,被編譯放在代碼段 .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_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);// 程序池,占用核心堆,記憶體池配置設定 
          if (g_processCBArray == NULL) {
              return LOS_NOK;
          }
          (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++) {//程序池循環建立
              g_processCBArray[index].processID = index;//程序ID[0-g_processMaxNum-1]指派
              g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;// 預設都是白紙一張,貼上未使用标簽
              LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList);//注意g_freeProcess挂的是pendList節點,是以使用要通過OS_PCB_FROM_PENDLIST找到程序實體.
          }
    
          g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 *///使用者态的根程序
          LOS_ListDelete(&g_processCBArray[g_userInitProcess].pendList);// 将1号程序從空閑連結清單上摘出去
    
          g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 *///核心态的根程序
          LOS_ListDelete(&g_processCBArray[g_kernelInitProcess].pendList);// 将2号程序從空閑連結清單上摘出去
    
          //注意:這波騷操作之後,g_freeProcess連結清單上還有,0,3,4,...g_processMaxNum-1号程序.建立程序是從g_freeProcess上申請
          //即下次申請到的将是0号程序,而 OsCreateIdleProcess 将占有0号程序.
    
          return LOS_OK;
      }
               

1号程序 init

1号程序為使用者态的老祖宗.建立過程如下, 省略了不相幹的代碼.

LITE_OS_SEC_TEXT_INIT INT32 OsMain(VOID)
{
    // ... 
    ret = OsKernelInitProcess();// 建立核心态根程序
    // ...
    ret = OsSystemInit(); //中間建立了使用者态根程序
}
UINT32 OsSystemInit(VOID)
{
    //..
    ret = OsSystemInitTaskCreate();//建立了一個系統任務,
}

STATIC UINT32 OsSystemInitTaskCreate(VOID)
{
    UINT32 taskID;
    TSK_INIT_PARAM_S sysTask;

    (VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit;//任務的入口函數,這個函數實作由外部提供
    sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K
    sysTask.pcName = "SystemInit";//任務的名稱
    sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;// 核心預設優先級為10 
    sysTask.uwResved = LOS_TASK_STATUS_DETACHED;//任務分離模式
#if (LOSCFG_KERNEL_SMP == YES)
    sysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());//cpu 親和性設定,記錄執行過任務的CPU,盡量確定由同一個CPU完成任務周期
#endif
    return LOS_TaskCreate(&taskID, &sysTask);//建立任務并加入就緒隊列,并立即參與排程
}
//SystemInit的實作由由外部提供 比如..\vendor\hi3516dv300\module_init\src\system_init.c
void SystemInit(void)
{
    // ...
    if (OsUserInitProcess()) {//建立使用者态程序的老祖宗
        PRINT_ERR("Create user init process faialed!\n");
        return;
    }
}
//使用者态根程序的建立過程
LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID)
{
    INT32 ret;
    UINT32 size;
    TSK_INIT_PARAM_S param = { 0 };
    VOID *stack = NULL;
    VOID *userText = NULL;
    CHAR *userInitTextStart = (CHAR *)&__user_init_entry;//代碼區開始位置 ,對應 LITE_USER_SEC_ENTRY
    CHAR *userInitBssStart = (CHAR *)&__user_init_bss;// 未初始化資料區(BSS)。在運作時改變其值 對應 LITE_USER_SEC_BSS
    CHAR *userInitEnd = (CHAR *)&__user_init_end;// 結束位址
    UINT32 initBssSize = userInitEnd - userInitBssStart;
    UINT32 initSize = userInitEnd - userInitTextStart;

    LosProcessCB *processCB = OS_PCB_FROM_PID(g_userInitProcess);//"Init程序的優先級是 28"
    ret = OsProcessCreateInit(processCB, OS_USER_MODE, "Init", OS_PROCESS_USERINIT_PRIORITY);// 初始化使用者程序,它将是所有應用程式的父程序
    if (ret != LOS_OK) {
        return ret;
    }

    userText = LOS_PhysPagesAllocContiguous(initSize >> PAGE_SHIFT);// 配置設定連續的實體頁
    if (userText == NULL) {
        ret = LOS_NOK;
        goto ERROR;
    }

    (VOID)memcpy_s(userText, initSize, (VOID *)&__user_init_load_addr, initSize);// 安全copy 經加載器load的結果 __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_PERM_EXECUTE | VM_MAP_REGION_FLAG_PERM_USER);// 虛拟位址與實體位址的映射
    if (ret < 0) {
        goto ERROR;
    }

    (VOID)memset_s((VOID *)((UINTPTR)userText + userInitBssStart - userInitTextStart), initBssSize, 0, initBssSize);// 除了代碼段,其餘都清0

    stack = OsUserInitStackAlloc(g_userInitProcess, &size);//配置設定任務在使用者态下的運作棧,大小為1M
    if (stack == NULL) {
        PRINTK("user init process malloc user stack failed!\n");
        ret = LOS_NOK;
        goto ERROR;
    }

    param.pfnTaskEntry = (TSK_ENTRY_FUNC)userInitTextStart;// 從代碼區開始執行,也就是應用程式main 函數的位置
    param.userParam.userSP = (UINTPTR)stack + size;// 使用者态棧底
    param.userParam.userMapBase = (UINTPTR)stack;// 使用者态棧頂
    param.userParam.userMapSize = size;// 使用者态棧大小
    param.uwResved = OS_TASK_FLAG_PTHREAD_JOIN;// 可結合的(joinable)能夠被其他線程收回其資源和殺死
    ret = OsUserInitProcessStart(g_userInitProcess, &param);// 建立一個任務,來運作main函數
    if (ret != LOS_OK) {
        (VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);
        goto ERROR;
    }

    return LOS_OK;

ERROR:
    (VOID)LOS_PhysPagesFreeContiguous(userText, initSize >> PAGE_SHIFT);//釋放實體記憶體塊
    OsDeInitPCB(processCB);//删除PCB塊
    return ret;
}
           
  • 從代碼中可以看出使用者态的老祖宗建立過程有點意思,首先它的源頭和核心态老祖宗一樣都在

    OsMain

    .
  • 通過建立一個分離模式,優先級為10的系統任務

    SystemInit

    ,來完成.任務的入口函數

    SystemInit()

    的實作由平台內建商來指定. 本篇采用了

    hi3516dv300

    的實作.也就是說使用者态祖宗的建立是在

    sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K

    棧中完成的.這個任務歸屬于核心程序

    KProcess

  • 使用者态老祖宗的名字叫

    Init

    ,優先級為28級.
  • 使用者态的每個程序有獨立的虛拟程序空間

    vmSpace

    ,擁有獨立的記憶體映射表(L1,L2表),申請的記憶體需要重新映射,映射過程在記憶體系列篇中有詳細的說明.
  • init

    建立了一個任務,任務的入口位址為

    __user_init_entry

    ,由編譯器指定.
  • 使用者态程序是指應有程式運作的程序,通過動态加載ELF檔案的方式啟動.具體加載流程系列篇有講解,不細說.使用者态程序運作在使用者空間,但通過系統調用可陷入核心空間.具體看這張圖:
    v46.05 鴻蒙核心源碼分析(特殊程式篇) | 龍生龍,鳳生鳳,老鼠生兒會打洞 | 百篇部落格分析OpenHarmony源碼

百篇部落格分析.深挖核心地基

  • 給鴻蒙核心源碼加注釋過程中,整理出以下文章。内容立足源碼,常以生活場景打比方盡可能多的将核心知識點置入某種場景,具有畫面感,容易了解記憶。說别人能聽得懂的話很重要! 百篇部落格絕不是百度教條式的在說一堆诘屈聱牙的概念,那沒什麼意思。更希望讓核心變得栩栩如生,倍感親切.确實有難度,自不量力,但已經出發,回頭已是不可能的了。 😛
  • 與代碼有bug需不斷debug一樣,文章和注解内容會存在不少錯漏之處,請多包涵,但會反複修正,持續更新,v**.xx 代表文章序号和修改的次數,精雕細琢,言簡意赅,力求打造精品内容。

按功能子產品:

基礎工具 加載運作 程序管理 編譯建構

雙向連結清單

位圖管理

用棧方式

定時器

原子操作

時間管理

ELF格式

ELF解析

靜态連結

重定位

程序映像

程序概念

Fork

特殊程序

程序回收

信号生産

信号消費

Shell編輯

Shell解析

編譯環境

編譯過程

環境腳本

建構工具

gn應用

忍者ninja

程序通訊 記憶體管理 前因後果 任務管理

自旋鎖

互斥鎖

信号量

事件控制

消息隊列

記憶體配置設定

記憶體彙編

記憶體映射

記憶體規則

實體記憶體

總目錄

排程故事

記憶體主奴

源碼注釋

源碼結構

靜态站點

時鐘任務

任務排程

排程隊列

排程機制

線程概念

并發并行

CPU

系統調用

任務切換

檔案系統 硬體架構

檔案概念

索引節點

挂載目錄

根檔案系統

字元裝置

VFS

檔案句柄

管道檔案

彙編基礎

彙編傳參

工作模式

寄存器

異常接管

彙編彙總

中斷切換

中斷概念

中斷管理

百萬漢字注解.精讀核心源碼

四大碼倉中文注解 . 定期同步官方代碼

v46.05 鴻蒙核心源碼分析(特殊程式篇) | 龍生龍,鳳生鳳,老鼠生兒會打洞 | 百篇部落格分析OpenHarmony源碼

鴻蒙研究站( weharmonyos ) | 每天死磕一點點,原創不易,歡迎轉載,請注明出處。若能支援點贊更好,感謝每一份支援。

繼續閱讀