0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙内核源码分析之定时器的状态、分类、管理

鸿蒙系统HarmonyOS 来源:my.oschina 作者: 鸿蒙内核源码分析 2021-04-25 17:01 次阅读

运作机制

软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器。当经过设定的Tick数后,会触发用户自定义的回调函数。

软件定时器是系统资源,在模块初始化的时候已经分配了一块连续内存。

软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先触发的准则。

软件定时器以Tick为基本计时单位,当创建并启动一个软件定时器时,鸿蒙会根据当前系统Tick时间及设置的定时时长确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。

当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,检查是否有定时器超时,

若有则将超时的定时器记录下来。Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用已经记录下来的定时器的回调函数。

定时器长什么样?

typedef VOID (*SWTMR_PROC_FUNC)(UINTPTR arg);//函数指针, 赋值给 SWTMR_CTRL_S->pfnHandler,回调处理
typedef struct tagSwTmrCtrl {//软件定时器控制块
    SortLinkList stSortList;//通过它挂到对应CPU核定时器链表上
    UINT8 ucState;      /**< Software timer state *///软件定时器的状态
    UINT8 ucMode;       /**< Software timer mode *///软件定时器的模式
    UINT8 ucOverrun;    /**< Times that a software timer repeats timing *///软件定时器重复计时的次数
    UINT16 usTimerID;   /**< Software timer ID *///软件定时器ID,唯一标识,由软件计时器池分配
    UINT32 uwCount;     /**< Times that a software timer works *///软件定时器工作的时间
    UINT32 uwInterval;  /**< Timeout interval of a periodic software timer *///周期性软件定时器的超时间隔
    UINT32 uwExpiry;    /**< Timeout interval of an one-off software timer *///一次性软件定时器的超时间隔
#if (LOSCFG_KERNEL_SMP == YES)
    UINT32 uwCpuid;     /**< The cpu where the timer running on *///多核情况下,定时器运行的cpu
#endif
    UINTPTR uwArg;      /**< Parameter passed in when the callback function
                             that handles software timer timeout is called *///回调函数的参数
    SWTMR_PROC_FUNC pfnHandler; /**< Callback function that handles software timer timeout */	//处理软件计时器超时的回调函数
    UINT32          uwOwnerPid; /** Owner of this software timer *///软件定时器所属进程ID号
} SWTMR_CTRL_S;//变量前缀 uc:UINT8  us:UINT16 uw:UINT32

解读

在多CPU核情况下,定时器是跟着CPU走的,每个CPU核都维护着独立的定时任务链表,上面挂的都是CPU核要处理的定时器.

stSortList的背后是双向链表,这对钩子在定时器创建的那一刻会钩到CPU的swtmrSortLink上去.

pfnHandler定时器时间到了的执行函数,由外界指定.uwArg为回调函数的参数

ucMode为定时器模式,软件定时器提供了三类模式

单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。 周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。 单次触发定时器,但这类定时器超时触发后不会自动删除,需要调用定时器删除接口删除定时器。

ucState定时器状态.

OS_SWTMR_STATUS_UNUSED(定时器未使用) 系统在定时器模块初始化时,会将系统中所有定时器资源初始化成该状态。 OS_SWTMR_STATUS_TICKING(定时器处于计数状态) 在定时器创建后调用LOS_SwtmrStart接口启动,定时器将变成该状态,是定时器运行时的状态。 OS_SWTMR_STATUS_CREATED(定时器创建后未启动,或已停止) 定时器创建后,不处于计数状态时,定时器将变成该状态。

定时器分类

定时器是指从指定的时刻开始,经过一定的指定时间后触发一个事件,例如定个时间提醒晚上9点准时秒杀。定时器有硬件定时器和软件定时器之分:

硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。

软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。

鸿蒙内核提供软件实现的定时器,以时钟节拍(OS Tick)的时间长度为单位,即定时数值必须是 OS Tick 的整数倍,例如鸿蒙内核默认是10ms触发一次,那么上层软件定时器只能是 10ms,20ms,100ms 等,而不能定时为 15ms。

定时器怎么管理?

LITE_OS_SEC_BSS SWTMR_CTRL_S    *g_swtmrCBArray = NULL;     /* First address in Timer memory space *///定时器池
LITE_OS_SEC_BSS UINT8           *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler *///用于注册软时钟的回调函数
LITE_OS_SEC_BSS LOS_DL_LIST     g_swtmrFreeList;            /* Free list of Software Timer *///空闲定时器链表

typedef struct {//处理软件定时器超时的回调函数的结构体
    SWTMR_PROC_FUNC handler;    /**< Callback function that handles software timer timeout  */	//处理软件定时器超时的回调函数
    UINTPTR arg;                /**< Parameter passed in when the callback function
                                    that handles software timer timeout is called */	//调用处理软件计时器超时的回调函数时传入的参数
} SwtmrHandlerItem;

解读三个全局变量可知,定时器是通过池来管理,在初始化阶段赋值.

g_swtmrCBArray定时器池,初始化中一次性创建1024个定时器控制块供使用

g_swtmrHandlerPool回调函数池,回调函数也是统一管理的,申请了静态内存保存. 池中放的是SwtmrHandlerItem回调函数描述符.

g_swtmrFreeList空闲可供分配的定时器链表,鸿蒙的进程池,任务池,事件池都是这么处理的,没有印象的自行去 鸿蒙内核源码分析(总目录)< OSCHINA | CSDN >翻看.g_swtmrFreeList上挂的是一个个的SWTMR_CTRL_S

要搞明白SWTMR_CTRL_S和SwtmrHandlerItem的关系,前者是一个定时器,后者是定时器时间到了去哪里干活.

初始化 -> OsSwtmrInit

o4YBAGCFL8GALCIQAADrSvg0k10281.png

#define LOSCFG_BASE_CORE_SWTMR_LIMIT 1024 // 最大支持的软件定时器数
LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID)
{
    UINT32 size;
    UINT16 index;
    UINT32 ret;
    SWTMR_CTRL_S *swtmr = NULL;
    UINT32 swtmrHandlePoolSize;
    UINT32 cpuid = ArchCurrCpuid();
    if (cpuid == 0) {//确保以下代码块由一个CPU执行,g_swtmrCBArray和g_swtmrHandlerPool 是所有CPU共用的
        size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT;//申请软时钟内存大小 
        swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); /* system resident resource */ //常驻内存
        if (swtmr == NULL) {
            return LOS_ERRNO_SWTMR_NO_MEMORY;
        }

        (VOID)memset_s(swtmr, size, 0, size);//清0
        g_swtmrCBArray = swtmr;//软时钟
        LOS_ListInit(&g_swtmrFreeList);//初始化空闲链表
        for (index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
            swtmr->usTimerID = index;//按顺序赋值
            LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表 
        }
        //想要用静态内存池管理,就必须要使用LOS_MEMBOX_SIZE来计算申请的内存大小,因为需要点前缀内存承载头部信息.
        swtmrHandlePoolSize = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);//计算所有注册函数内存大小
        //规划一片内存区域作为软时钟处理函数的静态内存池。
        g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, swtmrHandlePoolSize); /* system resident resource *///常驻内存
        if (g_swtmrHandlerPool == NULL) {
            return LOS_ERRNO_SWTMR_NO_MEMORY;
        }

        ret = LOS_MemboxInit(g_swtmrHandlerPool, swtmrHandlePoolSize, sizeof(SwtmrHandlerItem));//初始化软时钟注册池
        if (ret != LOS_OK) {
            return LOS_ERRNO_SWTMR_HANDLER_POOL_NO_MEM;
        }
    }
    //每个CPU都会创建一个属于自己的 OS_SWTMR_HANDLE_QUEUE_SIZE 的队列
    ret = LOS_QueueCreate(NULL, OS_SWTMR_HANDLE_QUEUE_SIZE, &g_percpu[cpuid].swtmrHandlerQueue, 0, sizeof(CHAR *));//为当前CPU core 创建软时钟队列 maxMsgSize:sizeof(CHAR *)
    if (ret != LOS_OK) {
        return LOS_ERRNO_SWTMR_QUEUE_CREATE_FAILED;
    }

    ret = OsSwtmrTaskCreate();//每个CPU独自创建属于自己的软时钟任务,统一处理队列
    if (ret != LOS_OK) {
        return LOS_ERRNO_SWTMR_TASK_CREATE_FAILED;
    }

    ret = OsSortLinkInit(&g_percpu[cpuid].swtmrSortLink);//每个CPU独自对自己软时钟链表排序初始化,为啥要排序因为每个定时器的时间不一样,鸿蒙把用时短的排在前面
    if (ret != LOS_OK) {
        return LOS_ERRNO_SWTMR_SORTLINK_CREATE_FAILED;
    }

    return LOS_OK;
}

代码解读:

每个CPU核都是独立处理定时器任务的,所以需要独自管理.OsSwtmrInit是负责初始化各CPU核定时模块功能的,注意在多CPU核时,OsSwtmrInit会被多次调用.

cpuid == 0代表主CPU核, 它最早执行这个函数,所以g_swtmrCBArray和g_swtmrHandlerPool是共用的,系统默认最多支持 1024 个定时器和回调函数.

每个CPU核都创建了自己独立的LOS_QueueCreate队列和任务OsSwtmrTaskCreate,并初始化了swtmrSortLink链表,关于链表排序可前往系列篇总目录 排序链表篇查看.

定时任务 -> 最高优先级

LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrTaskCreate(VOID)
{
    UINT32 ret, swtmrTaskID;
    TSK_INIT_PARAM_S swtmrTask;
    UINT32 cpuid = ArchCurrCpuid();//获取当前CPU id

    (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//清0
    swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)OsSwtmrTask;//入口函数
    swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K默认内核任务栈
    swtmrTask.pcName = "Swt_Task";//任务名称
    swtmrTask.usTaskPrio = 0;//哇塞! 逮到一个最高优先级的任务 @note_thinking 这里应该用 OS_TASK_PRIORITY_HIGHEST 表示
    swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;//分离模式
#if (LOSCFG_KERNEL_SMP == YES)
    swtmrTask.usCpuAffiMask   = CPUID_TO_AFFI_MASK(cpuid);//交给当前CPU执行这个任务
#endif
    ret = LOS_TaskCreate(&swtmrTaskID, &swtmrTask);//创建任务并申请调度
    if (ret == LOS_OK) {
        g_percpu[cpuid].swtmrTaskID = swtmrTaskID;//全局变量记录 软时钟任务ID
        OS_TCB_FROM_TID(swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//告知这是一个系统任务
    }

    return ret;
}

代码解读:

内核为每个CPU处理单独创建任务来处理定时器, 任务即线程, 外界可理解为内核开设了一个线程跑定时器.

注意看任务的优先级swtmrTask.usTaskPrio = 0;0是最高优先级! 这并不多见! 内核会在第一时间响应软时钟任务.

系列篇CPU篇中讲过每个CPU都有自己的任务链表和定时器任务,g_percpu[cpuid].swtmrTaskID = swtmrTaskID;表示创建的任务和CPU具体核进行了捆绑.从此swtmrTaskID负责这个CPU的定时器处理.

定时任务是一个系统任务,除此之外还有哪些是系统任务?

任务入口函数OsSwtmrTask,是任务的执行体,类似于[Java 线程中的run()函数]

usCpuAffiMask代表这个任务只能由这个CPU核来跑

队列消费者 -> OsSwtmrTask

//软时钟的入口函数,拥有任务的最高优先级 0 级!
LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID)
{
    SwtmrHandlerItemPtr swtmrHandlePtr = NULL;
    SwtmrHandlerItem swtmrHandle;
    UINT32 ret, swtmrHandlerQueue;

    swtmrHandlerQueue = OsPercpuGet()->swtmrHandlerQueue;//获取定时器超时队列
    for (;;) {//死循环获取队列item,一直读干净为止
        ret = LOS_QueueRead(swtmrHandlerQueue, &swtmrHandlePtr, sizeof(CHAR *), LOS_WAIT_FOREVER);//一个一个读队列
        if ((ret == LOS_OK) && (swtmrHandlePtr != NULL)) {
            swtmrHandle.handler = swtmrHandlePtr->handler;//超时中断处理函数,也称回调函数
            swtmrHandle.arg = swtmrHandlePtr->arg;//回调函数的参数
            (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);//静态释放内存,注意在鸿蒙内核只有软时钟注册用到了静态内存
            if (swtmrHandle.handler != NULL) {
                swtmrHandle.handler(swtmrHandle.arg);//回调函数处理函数
            }
        }
    }
}

代码解读:

OsSwtmrTask是任务的执行体,只做一件事,消费定时器回调函数队列.

任务在跑一个死循环,不断在读队列.关于队列的具体操作不在此处细说,系列篇中已有专门的文章讲解,可前往查看.

每个CPU核都有属于自己的定时器回调函数队列,里面存放的是时间到了回调函数.

但队列的数据怎么来呢?OsSwtmrTask只是在不断的消费队列,那生产者在哪里呢? 就是OsSwtmrScan

队列生产者 -> OsSwtmrScan

LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID)//扫描定时器,如果碰到超时的,就放入超时队列
{
    SortLinkList *sortList = NULL;
    SWTMR_CTRL_S *swtmr = NULL;
    SwtmrHandlerItemPtr swtmrHandler = NULL;
    LOS_DL_LIST *listObject = NULL;
    SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink;//拿到当前CPU的定时器链表

    swtmrSortLink->cursor = (swtmrSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = swtmrSortLink->sortLink + swtmrSortLink->cursor;
	//由于swtmr是在特定的sortlink中,所以需要很小心的处理它,但其他CPU Core仍然有机会处理它,比如停止计时器
    /*
     * it needs to be carefully coped with, since the swtmr is in specific sortlink
     * while other cores still has the chance to process it, like stop the timer.
     */
    LOS_SpinLock(&g_swtmrSpin);

    if (LOS_ListEmpty(listObject)) {
        LOS_SpinUnlock(&g_swtmrSpin);
        return;
    }
    sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    ROLLNUM_DEC(sortList->idxRollNum);

    while (ROLLNUM(sortList->idxRollNum) == 0) {
        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
        LOS_ListDelete(&sortList->sortLinkNode);
        swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);

        swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool);//取出一个可用的软时钟处理项
        if (swtmrHandler != NULL) {
            swtmrHandler->handler = swtmr->pfnHandler;
            swtmrHandler->arg = swtmr->uwArg;

            if (LOS_QueueWrite(OsPercpuGet()->swtmrHandlerQueue, swtmrHandler, sizeof(CHAR *), LOS_NO_WAIT)) {
                (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandler);
            }
        }

        if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) {
            OsSwtmrDelete(swtmr);

            if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) {
                swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT;
            } else {
                swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT;
            }
        } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) {
            swtmr->ucState = OS_SWTMR_STATUS_CREATED;
        } else {
            swtmr->ucOverrun++;
            OsSwtmrStart(swtmr);
        }

        if (LOS_ListEmpty(listObject)) {
            break;
        }

        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    }

    LOS_SpinUnlock(&g_swtmrSpin);
}

代码解读:

OsSwtmrScan 函数是在系统时钟处理函数OsTickHandler中调用的,它就干一件事,不停的比较定时器是否超时

一旦超时就把定时器的回调函数扔到队列中,让OsSwtmrTask去消费.

总结

定时器池g_swtmrCBArray存储内核所有的定时器,默认1024个,各CPU共享这个池

定时器响应函数池g_swtmrHandlerPool存储内核所有的定时器响应函数,默认1024个,各CPU也共享这个池

每个CPU核都有独立的任务(线程)来处理定时器, 这个任务叫定时任务

每个CPU核都有独立的响应函数队列swtmrHandlerQueue,队列中存放该核时间到了的响应函数SwtmrHandlerItem

定时任务的优先级最高,循环读取队列swtmrHandlerQueue,swtmrHandlerQueue中存放是定时器时间到了的响应函数.并一一回调这些响应函数.

OsSwtmrScan负责扫描定时器的时间是否到了,到了就往队列swtmrHandlerQueue中扔.

定时器有多种模式,包括单次,循环.所以循环类定时器的响应函数会多次出现在swtmrHandlerQueue中.

编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 定时器
    +关注

    关注

    23

    文章

    3148

    浏览量

    112040
  • 系统时钟
    +关注

    关注

    1

    文章

    30

    浏览量

    9013
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2620

    浏览量

    65273
收藏 人收藏

    评论

    相关推荐

    【HarmonyOS】鸿蒙内核源码分析(调度机制篇)

    task交给CPU处理,那是什么让调度去工作的呢?它是如何被触发的?笔者能想到的触发方式是以下四个:Tick(时钟管理),类似于JAVA的定时任务,时间到了就触发。系统定时器内核时间
    发表于 10-14 14:00

    鸿蒙内核源码分析:用通俗易懂的语言告诉你鸿蒙内核发生了什么?

    是:鸿蒙内核源码分析(内存概念篇)| 鸿蒙内核源码
    发表于 11-19 10:14

    鸿蒙内核源码分析源码注释篇):给HarmonyOS源码逐行加上中文注释

    都懂的概念去诠释或者映射一个他们从没听过的概念.说别人能听得懂的话这很重要!!! 一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? NO!,笔者在系列篇中试图用 鸿蒙源码分析
    发表于 11-19 10:32

    鸿蒙源码分析系列(总目录) | 给HarmonyOS源码逐行加上中文注释

    同步更新。鸿蒙源码分析系列篇|- 鸿蒙内核源码分析
    发表于 11-20 11:24

    鸿蒙内核源码分析(内存概念篇) :手眼通天的虚拟内存

    分析(内存管理篇) | 鸿蒙内核源码分析(内存汇编篇) |鸿
    发表于 11-20 13:52

    鸿蒙内核源码分析(内存概念篇) :手眼通天的虚拟内存

    管理篇) | 鸿蒙内核源码分析(内存汇编篇) |鸿蒙内核
    发表于 11-20 16:30

    鸿蒙内核源码分析(必读篇):用故事说内核

    的工作原理!操作系统就是管理场馆和确保工作人员有序工作的系统解决方案商,外面公司只要提供个节目单,就能按节目单把这台戏演好给广大观众观看。有了这个故事垫底,鸿蒙内核源码
    发表于 11-23 10:15

    鸿蒙内核源码分析(调度机制篇):Task是如何被调度执行的

    下四个:Tick(时钟管理),类似于JAVA的定时任务,时间到了就触发。系统定时器内核时间机制中最重要的一部分,它提供了一种周期性触发中断机制,即系统
    发表于 11-23 10:53

    鸿蒙内核源码分析(必读篇)

    的工作原理!操作系统就是管理场馆和确保工作人员有序工作的系统解决方案商,外面公司只要提供个节目单,就能按节目单把这台戏演好给广大观众观看。有了这个故事垫底,鸿蒙内核源码
    发表于 11-25 09:28

    Linux和RTOS的时钟和定时器怎么使用

    Linux发烧友1.RTOS篇1.1RT-Thread简介1.2时钟管理1.2.1时钟节拍1.3获取系统节拍1.4定时器分类1.5定时器源码
    发表于 01-17 08:13

    鸿蒙内核源码分析鸿蒙内核的每段汇编代码解析

    本篇说清楚CPU的工作模式 读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇. 正如一个互联网项目的后台管理系统有权限
    的头像 发表于 03-02 09:56 3731次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b>:<b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b>的每段汇编代码解析

    鸿蒙内核源码分析: 虚拟内存和物理内存是怎么管理

    有了上篇鸿蒙内核源码分析(内存概念篇)的基础,本篇讲内存管理部分,本章源码超级多,很烧脑,但笔者
    发表于 11-23 11:45 19次下载
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b>: 虚拟内存和物理内存是怎么<b class='flag-5'>管理</b>的

    鸿蒙内核源码分析:时钟是触发调度最大的源动力

    时钟管理模块很简单,但却有内核最重要的代码段 OsTickHandler(),这是干嘛的,可以理解为 JAVA的定时任务,但这是系统内核定时器
    发表于 11-24 17:50 31次下载
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b>:时钟是触发调度最大的源动力

    鸿蒙内核源码分析内核最重要结构体

    为何鸿蒙内核源码分析系列开篇就说 LOS_DL_LIST ? 因为它在鸿蒙 LOS 内核中无处
    发表于 11-24 17:54 35次下载
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b> :<b class='flag-5'>内核</b>最重要结构体

    华为鸿蒙系统内核源码分析上册

    鸿蒙內核源码注释中文版【 Gitee仓】给 Harmoηy○S源码逐行加上中文注解,详细阐述设计细节,助你快速精读 Harmonyos内核源码
    发表于 04-09 14:40 16次下载