Hongmeng kernel source code analysis (timer mechanism) | who is the highest priority task of the kernel| Chinese annotation HarmonyOS source code | V31 01

Million Chinese character annotation > > intensive reading kernel source code, Chinese annotation analysis, deep foundation engineering, permanent brain memory, and four code warehouses are updated synchronously every day < Gitee | Github | CSDN | Coding >

One hundred blog Analysis > > story telling kernel, Q & a guide, life style metaphor, tabular description, graphical display, multi site daily synchronous update < OSCHINA | CSDN | WeHarmony >

This article explains the implementation of timer clearly

It is recommended to read this article before reading it Hongmeng kernel source code analysis (general directory) The rest

Operation mechanism

  • Software timer is a timer based on system Tick clock interrupt and simulated by software. After the set number of ticks, the user-defined callback function will be triggered.
  • Software timer is a system resource. A continuous memory has been allocated when the module is initialized.
  • The software timer uses a queue and a task resource of the system. The trigger of the software timer follows the queue rules and is first in first out. The timer with short timing time is always closer to the queue head than the timer with long timing time, which meets the criterion of priority triggering.
  • The software timer takes Tick as the basic timing unit. When creating and starting a software timer, Hongmeng will determine the expiration Tick time of the timer according to the current system Tick time and the set timing duration, and hang the timer control structure into the timing global linked list.
  • When the Tick interrupt arrives, scan the timing global linked list of the software timer in the Tick interrupt processing function to check whether there is a timer timeout,
  • If so, record the timeout timer. After the Tick interrupt processing function is finished, the software timer task (the highest priority is) is waken up, and the callback function of the timer has been invoked in the middle note.

What does the timer look like?

typedef VOID (*SWTMR_PROC_FUNC)(UINTPTR arg);//Function pointer, assigned to swtmr_ CTRL_ S - > pfnhandler, callback processing
typedef struct tagSwTmrCtrl {//Software timer control block
    SortLinkList stSortList;//Hang it to the linked list of corresponding CPU core timers
    UINT8 ucState;      /**< Software timer state *///Status of software timer
    UINT8 ucMode;       /**< Software timer mode *///Mode of software timer
    UINT8 ucOverrun;    /**< Times that a software timer repeats timing *///The number of times the software timer repeats
    UINT16 usTimerID;   /**< Software timer ID *///Software timer ID, unique identification, allocated by software timer pool
    UINT32 uwCount;     /**< Times that a software timer works *///Working time of software timer
    UINT32 uwInterval;  /**< Timeout interval of a periodic software timer *///Timeout interval of periodic software timer
    UINT32 uwExpiry;    /**< Timeout interval of an one-off software timer *///Timeout interval of one-time software timer
#if (LOSCFG_KERNEL_SMP == YES)
    UINT32 uwCpuid;     /**< The cpu where the timer running on *///In the case of multi-core, the cpu in which the timer runs
#endif
    UINTPTR uwArg;      /**< Parameter passed in when the callback function
                             that handles software timer timeout is called *///Parameters of callback function
    SWTMR_PROC_FUNC pfnHandler; /**< Callback function that handles software timer timeout */	//Callback function to handle software timer timeout
    UINT32          uwOwnerPid; /** Owner of this software timer *///Process ID number of software timer
} SWTMR_CTRL_S;//Variable prefix UC: uint8 us: uint16 UW: uint32

unscramble

  • In the case of multiple CPU cores, the timer follows the CPU. Each CPU core maintains an independent timed task list, on which are the timers to be processed by the CPU core

  • Behind the stSortList is a two-way linked list. This pair of hooks will hook to the swtmrSortLink of the CPU at the moment when the timer is created

  • The execution function of pfnHandler timer, which is specified by the outside world uwArg is the parameter of the callback function

  • ucMode is timer mode, and software timer provides three modes

    Single trigger timer, this kind of timer will only trigger a timer event after starting, and then the timer will be deleted automatically.

    Periodic trigger timer, which will trigger timer events periodically until the user manually stops the timer, otherwise it will continue to execute forever.

    The timer is triggered once, but it will not be deleted automatically after it is triggered. It is necessary to call the timer deletion interface to delete the timer.

  • ucState timer state

    OS_SWTMR_STATUS_UNUSED (timer not used)

    When the timer module is initialized, the system will initialize all timer resources in the system to this state.

    OS_SWTMR_STATUS_TICKING (timer in counting state)

    Call LOS_ after the timer is created. Base note When the swtmrstart interface is started, the timer will change to this state, which is the state when the timer is running.

    OS_SWTMR_STATUS_CREATED (timer not started or stopped after creation)

    After the timer is created, when it is not in the counting state, the timer will change to this state.

How to manage the timer?

  •   LITE_OS_SEC_BSS SWTMR_CTRL_S    *g_swtmrCBArray = NULL;     /* First address in Timer memory space *///Timer pool
      LITE_OS_SEC_BSS UINT8           *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler *///Callback function for registering soft clock
      LITE_OS_SEC_BSS LOS_DL_LIST     g_swtmrFreeList;            /* Free list of Software Timer *///Idle timer linked list
    
      typedef struct {//Structure of callback function for processing software timer timeout
          SWTMR_PROC_FUNC handler;    /**< Callback function that handles software timer timeout  */	//Callback function for processing software timer timeout
          UINTPTR arg;                /**< Parameter passed in when the callback function
                                          that handles software timer timeout is called */	//The parameter passed in when calling the callback function that handles the timeout of the software timer
      } SwtmrHandlerItem;
    

By interpreting the three global variables, we can see that the timer is managed through the pool and assigned value in the initialization stage

  • g_swtmrCBArray timer pool. 1024 timer control blocks are created for use at one time during initialization
  • g_swtmrHandlerPool callback function pool, which is also managed uniformly, applies for static memory storage SwtmrHandlerItem callback function descriptor is placed in the pool
  • g_swtmrFreeList idle timer list available for allocation, Hongmeng process pool, task pool and event pool are handled in this way. If you are not impressed, go to Hongmeng kernel source code analysis (general directory) < OSCHINA | CSDN > Look through g_swtmrFreeList is hung with swtmrs one by one_ CTRL_ S
  • To understand swtmr_ CTRL_ The relationship between S and SwtmrHandlerItem is that the former is a timer and the latter is where to work when the timer time is up

Initialization - > osswtmrinit

#define LOSCFG_BASE_CORE_SWTMR_LIMIT 1024 / / the maximum number of software timers supported
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) {//Ensure that the following code blocks are executed by one CPU, g_swtmrCBArray and g_swtmrHandlerPool is shared by all CPUs
        size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT;//Apply for soft clock memory size 
        swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); /* system resident resource */ //memory-resident
        if (swtmr == NULL) {
            return LOS_ERRNO_SWTMR_NO_MEMORY;
        }

        (VOID)memset_s(swtmr, size, 0, size);//Clear 0
        g_swtmrCBArray = swtmr;//Soft clock
        LOS_ListInit(&g_swtmrFreeList);//Initialize free linked list
        for (index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
            swtmr->usTimerID = index;//Assign values in order
            LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//Hang the node to the free linked list through sortLinkNode 
        }
        //If you want to use static memory pool management, you must use LOS_MEMBOX_SIZE to calculate the requested memory size, because the point prefix memory is required to carry the header information
        swtmrHandlePoolSize = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);//Calculate the memory size of all registered functions
        //Plan a memory area as a static memory pool for soft clock processing function.
        g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, swtmrHandlePoolSize); /* system resident resource *///memory-resident
        if (g_swtmrHandlerPool == NULL) {
            return LOS_ERRNO_SWTMR_NO_MEMORY;
        }

        ret = LOS_MemboxInit(g_swtmrHandlerPool, swtmrHandlePoolSize, sizeof(SwtmrHandlerItem));//Initialize soft clock registration pool
        if (ret != LOS_OK) {
            return LOS_ERRNO_SWTMR_HANDLER_POOL_NO_MEM;
        }
    }
    //Each CPU will create its own OS_SWTMR_HANDLE_QUEUE_SIZE queue
    ret = LOS_QueueCreate(NULL, OS_SWTMR_HANDLE_QUEUE_SIZE, &g_percpu[cpuid].swtmrHandlerQueue, 0, sizeof(CHAR *));//Create a soft clock queue maxMsgSize:sizeof(CHAR *) for the current CPU core
    if (ret != LOS_OK) {
        return LOS_ERRNO_SWTMR_QUEUE_CREATE_FAILED;
    }

    ret = OsSwtmrTaskCreate();//Each CPU creates its own soft clock task independently and processes the queue uniformly
    if (ret != LOS_OK) {
        return LOS_ERRNO_SWTMR_TASK_CREATE_FAILED;
    }

    ret = OsSortLinkInit(&g_percpu[cpuid].swtmrSortLink);//Each CPU sorts and initializes its own soft clock linked list alone. Why should it be sorted? Because the time of each timer is different, Hongmeng ranks the short time in the front
    if (ret != LOS_OK) {
        return LOS_ERRNO_SWTMR_SORTLINK_CREATE_FAILED;
    }

    return LOS_OK;
}

Code interpretation:

  • Each CPU core handles timer tasks independently, so it needs to be managed independently OsSwtmrInit is responsible for initializing the module functions when each CPU is approved. Note that in case of multiple CPU cores, OsSwtmrInit will be called many times
  • cpuid == 0 represents the main CPU core, which first executes this function, so g_swtmrCBArray and g_swtmrHandlerPool is shared. By default, the system supports up to 1024 timers and callback functions
  • Each CPU core creates its own independent LOS_QueueCreate queue and task OsSwtmrTaskCreate, and initialize the swtmrSortLink linked list. For the sorting of the linked list, you can go to the sorting linked list of the general catalogue of series articles

Scheduled task - > highest priority

LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrTaskCreate(VOID)
{
    UINT32 ret, swtmrTaskID;
    TSK_INIT_PARAM_S swtmrTask;
    UINT32 cpuid = ArchCurrCpuid();//Get current CPU id

    (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//Clear 0
    swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)OsSwtmrTask;//Entry function
    swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K default kernel task stack
    swtmrTask.pcName = "Swt_Task";//Task name
    swtmrTask.usTaskPrio = 0;//WOW! Catch a task with the highest priority @ note_thinking should use OS here_ TASK_ PRIORITY_ Highest indicates
    swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;//Separation mode
#if (LOSCFG_KERNEL_SMP == YES)
    swtmrTask.usCpuAffiMask   = CPUID_TO_AFFI_MASK(cpuid);//Give it to the current CPU to perform this task
#endif
    ret = LOS_TaskCreate(&swtmrTaskID, &swtmrTask);//Create tasks and request scheduling
    if (ret == LOS_OK) {
        g_percpu[cpuid].swtmrTaskID = swtmrTaskID;//Global variable record soft clock task ID
        OS_TCB_FROM_TID(swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//Inform that this is a system task
    }

    return ret;
}

Code interpretation:

  • The kernel creates separate tasks for each CPU to process timers. Tasks are threads. It can be understood that the kernel sets up a thread running timer
  • Pay attention to the priority of the task swtmrtask usTaskPrio = 0; 0 is the highest priority! This is rare! The kernel will respond to the soft clock task at the first time
  • As mentioned in the CPU series, each CPU has its own task linked list and timer task, g_percpu[cpuid].swtmrTaskID = swtmrTaskID; Indicates that the created task is bundled with the CPU specific core From then on, swtmrtaskid is responsible for the timer processing of this CPU
  • A scheduled task is a system task. What else are system tasks?
  • The task entry function OsSwtmrTask is the execution body of the task, similar to [run() function in Java thread]
  • usCpuAffiMask means that this task can only be run by this CPU core

Queue consumer - > osswtmrtask

//The entry function of the soft clock has the highest priority level 0 of the task!
LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID)
{
    SwtmrHandlerItemPtr swtmrHandlePtr = NULL;
    SwtmrHandlerItem swtmrHandle;
    UINT32 ret, swtmrHandlerQueue;

    swtmrHandlerQueue = OsPercpuGet()->swtmrHandlerQueue;//Get timer timeout queue
    for (;;) {//Get the queue item in an endless loop until it is read completely
        ret = LOS_QueueRead(swtmrHandlerQueue, &swtmrHandlePtr, sizeof(CHAR *), LOS_WAIT_FOREVER);//One by one read queue
        if ((ret == LOS_OK) && (swtmrHandlePtr != NULL)) {
            swtmrHandle.handler = swtmrHandlePtr->handler;//Timeout interrupt processing function, also known as callback function
            swtmrHandle.arg = swtmrHandlePtr->arg;//Parameters of callback function
            (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);//Statically release the memory. Note that only the soft clock registration in Hongmeng kernel uses the static memory
            if (swtmrHandle.handler != NULL) {
                swtmrHandle.handler(swtmrHandle.arg);//Callback function handler
            }
        }
    }
}

Code interpretation:

  • OsSwtmrTask is the executive body of a task. It only does one thing, consuming the timer callback function queue
  • The task is running an endless loop, constantly reading the queue The specific operation of queue is not detailed here. There are special articles in the series, which can be viewed
  • Each CPU core has its own timer callback function queue, which stores the callback function when the time is up
  • But how does the queue data come from? OsSwtmrTask is just a constant consumption queue. Where are the producers? It's OsSwtmrScan

Scarosmn - > producer queue

LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID)//Scan timer. If it encounters timeout, it will be put into the timeout queue
{
    SortLinkList *sortList = NULL;
    SWTMR_CTRL_S *swtmr = NULL;
    SwtmrHandlerItemPtr swtmrHandler = NULL;
    LOS_DL_LIST *listObject = NULL;
    SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink;//Get the timer linked list of the current CPU

    swtmrSortLink->cursor = (swtmrSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = swtmrSortLink->sortLink + swtmrSortLink->cursor;
	//Because swtmr is in a specific sortlink, it needs to be handled with great care, but other CPU cores still have the opportunity to handle it, such as stopping the timer
    /*
     * 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);//Take out an available soft clock processing item
        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);
}

Code interpretation:

  • The OsSwtmrScan function is invoked in the middle note of the system clock processing function OsTickHandler. It does one thing, and constantly compares whether the timer is timed out.
  • Once the timer times out, the callback function of the timer is thrown into the queue for OsSwtmrTask to consume

summary

  • Timer pool G_ Swtmrcbrary stores all timers of the kernel, 1024 by default, and all CPU s share this pool

  • Timer response function pool g_swtmrHandlerPool stores all timer response functions of the kernel. By default, there are 1024. Each CPU also shares this pool

  • Each CPU core has an independent task (thread) to process the timer. This task is called timed task

  • Each CPU core has an independent response function queue swtmrHandlerQueue, which stores the response function SwtmrHandlerItem when the time of the core expires

  • The priority of the scheduled task is the highest. The circular reading queue swtmrhandlerqueue is stored in swtmrhandlerqueue, which is the response function when the timer time is up And call back these response functions one by one

  • OsSwtmrScan is responsible for scanning whether the timer time is up and throwing it into the queue swtmrHandlerQueue

  • The timer has many modes, including single and cycle Therefore, the response function of the loop timer will appear in swtmrHandlerQueue many times

Please collect if you like

Major sites search "Hongmeng kernel source code analysis" to quickly find the organization

Million Chinese character annotation > > intensive reading kernel source code, Chinese annotation analysis, deep foundation engineering, permanent brain memory, and four code warehouses are updated synchronously every day < Gitee | Github | CSDN | Coding >

One hundred blog Analysis > > story telling kernel, Q & a guide, life style metaphor, tabular description, graphical display, multi site daily synchronous update < OSCHINA | CSDN | WeHarmony >

Tags: C++ github gitee entry harmonyos liteos

Posted by sunnyvatsal on Tue, 19 Apr 2022 13:38:36 +0300