Hongmeng kernel source code analysis (two-way circular linked list) | opening tribute to Hongmeng kernel developers

Note: Based on core open source obscurity analysis, the official source [ kernel_liteos_a ] official documents [ docs ] Reference Document [ Huawei LiteOS ]
author: Hong Meng core enthusiasts, will continue to study obscurity kernel, update blog, so stay tuned. The content only represents personal views, errors are welcome, everyone is welcome to correct and improve. All articles in this series enter to view the  source code analysis of Hongmeng system (general catalog)


This article describes the two-way circular linked list in detail , see the source code: los_list.h 

table of Contents

Why did the Hongmeng kernel source code analysis series start with LOS_DL_LIST?

basic concepts

Function interface

Specific usage scenarios

Relevant code involved in the task queue

Inline function inline

All articles in this series enter Hongmeng system source code analysis (general catalog) view




Why did the Hongmeng kernel source code analysis series  start with LOS_DL_LIST ?

Because it is ubiquitous in the Hongmeng LOS kernel, it can be said that it occupies a huge proportion in the entire kernel. Basically, it sticks all the structures together like glue. It is not an exaggeration to understand LOS_DL_LIST and related functions. The key to understanding the core of Hongmeng. The front and back pointers are like two left and right hands of a person, directing the precise operation of the system. The more you analyze the kernel source code, the more you can experience the extraordinary ability of the kernel developers to control LOS_DL_LIST. The author seems to see countless hands connected back and forth. , Has pulled up countless two-way circular linked lists, and used the magic of the pointer to the extreme. Perhaps this is the art of programming!

To pay tribute to the developers of Hongmeng kernel, the source code of Hongmeng kernel can be used as a teaching project for two courses of university operating system and data structure.

/**
 * @ingroup los_list
 * Structure of a node in a doubly linked list.
 */
typedef struct LOS_DL_LIST {
    struct LOS_DL_LIST *pstPrev; /**< Current node's pointer to the previous node */
    struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node */
} LOS_DL_LIST;

LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
{
    list->pstNext = list;
    list->pstPrev = list;
}

Is it really everywhere? Answer: It is true. Look at the source code that uses it, everywhere.

basic concepts

A doubly linked list refers to a linked list with forward and backward directions, that is, in addition to storing the next node pointer, each node also adds a pointer to the previous node. The head pointer head is uniquely determined.

Starting from any node in the doubly linked list, you can easily access its predecessor and successor nodes. This form of data structure makes the doubly linked list more convenient to look up, especially for large amounts of data traversal. Due to the symmetry of the doubly linked list, various operations such as insertion and deletion can be completed conveniently, but the operations in the front and back directions need to be paid attention to.

Function interface

The doubly linked list module in Huawei LiteOS system provides users with the following interfaces.

Function classification

Interface name

description

Initialize the linked list

LOS_ListInit

Initialize the linked list.

Add node

LOS_ListAdd

Add the new node to the linked list.

Insert a node at the end of the linked list

LOS_ListTailInsert

Insert the node at the end of the doubly linked list.

Delete node

LOS_ListDelete

Delete the specified node from the linked list.

Determine whether the doubly linked list is empty

LOS_ListEmpty

Determine whether the linked list is empty.

Delete the node and initialize the linked list

LOS_ListDelInit

Delete the specified node from the linked list and use this node to initialize the linked list.

Insert linked list into linked list LOS_ListAddList Two circular linked lists into a large circular linked list
Insert node from the end LOS_ListTailInsert (LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert node from head LOS_ListHeadInsert (LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert the linked list from the end LOS_ListTailInsertList (LOS_DL_LIST *oldList, LOS_DL_LIST *newList)
Insert the linked list from the head LOS_ListTailInsertList (LOS_DL_LIST *oldList, LOS_DL_LIST *newList)

Hongmeng uses a two-way circular linked list to realize the association between the structure data structure, supports the insertion of the head and the end of a single node, and more subtle is that the linked list supports the insertion of another linked list, combining two circular linked lists into a large circular linked list, which is extremely Ingenious and simple. See the code for details

 //双向链表初始化
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
{
    list->pstNext = list; // 前后指针都指向自己
    list->pstPrev = list;
}

//链表判空,检查前后指针是否指向自己
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
{
    return (BOOL)(list->pstNext == list);
}

//从链表中删除节点
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
{
    node->pstNext->pstPrev = node->pstPrev;
    node->pstPrev->pstNext = node->pstNext;
    node->pstNext = NULL;
    node->pstPrev = NULL;
}

//指针互换,具体向双向循环链表中插入节点
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
{
    node->pstNext = list->pstNext;
    node->pstPrev = list;
    list->pstNext->pstPrev = node;
    list->pstNext = node;
}

// 两个循环链表合成一个大循环列表
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAddList(LOS_DL_LIST *oldList, LOS_DL_LIST *newList)
{
    // 先用临时指针记录头尾位置
    LOS_DL_LIST *oldListHead = oldList->pstNext;
    LOS_DL_LIST *oldListTail = oldList;
    LOS_DL_LIST *newListHead = newList;
    LOS_DL_LIST *newListTail = newList->pstPrev;
    // 前后指针完成切换
    oldListTail->pstNext = newListHead;
    newListHead->pstPrev = oldListTail;
    oldListHead->pstPrev = newListTail;
    newListTail->pstNext = oldListHead;
}
// 这里与其说插入不如说合并,同样支持从头或尾部合并
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsertList(LOS_DL_LIST *oldList, LOS_DL_LIST *newList)
{
    LOS_ListAddList(oldList->pstPrev, newList);
}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListHeadInsertList(LOS_DL_LIST *oldList, LOS_DL_LIST *newList)
{
    LOS_ListAddList(oldList, newList);
}

When you read the source code of the Hongmeng kernel, you need to bring LOS_DL_LIST to understand the relationship between the codes in real time, and imagine what the runtime scene is, you can experience the beauty of the kernel code.

Specific usage scenarios

Take a look at one of its usage scenarios, experience the designer's wonderful intentions, and upload the code.

typedef struct ProcessCB {
    CHAR                 processName[OS_PCB_NAME_LEN]; /**< Process name */
    UINT32               processID;                    /**< process ID = leader thread ID */
    UINT16               processStatus;                /**< [15:4] process Status; [3:0] The number of threads currently
                                                            running in the process */
    LOS_DL_LIST          pendList;                     /**< Block list to which the process belongs */
    LOS_DL_LIST          childrenList;                 /**< my children process list */
    LOS_DL_LIST          exitChildList;                /**< my exit children process list */
    LOS_DL_LIST          siblingList;                  /**< linkage in my parent's children list */
    ProcessGroup         *group;                       /**< Process group to which a process belongs */
    LOS_DL_LIST          subordinateGroupList;         /**< linkage in my group list */
    UINT32               threadGroupID;                /**< Which thread group , is the main thread ID of the process */
    UINT32               threadScheduleMap;            /**< The scheduling bitmap table for the thread group of the
                                                            process */
    LOS_DL_LIST          threadSiblingList;            /**< List of threads under this process */
    LOS_DL_LIST          threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the

    LOS_DL_LIST          waitList;     /**< The process holds the waitLits to support 
} LosProcessCB;

This is LosProcessCB (process control block), because the structure is very complicated, and other definitions are omitted, leaving LOS_DL_LIST related. You can read the kernel source code by yourself. LosProcessCB contains seven two-way circular linked lists, and the queue of the process group is an array , And contains a doubly circular linked list of 32 ready queues. These linked lists carry the running process logic of a process in the life cycle, the relationship logic between the process and the thread, the running process logic of the thread, etc. Yes, such a complicated data structure is necessary to describe the process from birth to death the process of.

Relevant code involved in the task queue

These are the operations for the task queue to dequeue and enter the queue. Behind it is the process of adding and deleting LOS_DL_LIST. Please calm down and understand these macros.

#define OS_PROCESS_PRI_QUEUE_SIZE(processCB) OsPriQueueProcessSize(g_priQueueList, (processCB)->priority)

#define OS_TASK_PRI_QUEUE_ENQUEUE(processCB, taskCB) \
    OsPriQueueEnqueue((processCB)->threadPriQueueList, &((processCB)->threadScheduleMap), \
                      &((taskCB)->pendList), (taskCB)->priority)
#define OS_TASK_PRI_QUEUE_ENQUEUE_HEAD(processCB, taskCB) \
    OsPriQueueEnqueueHead((processCB)->threadPriQueueList, &((processCB)->threadScheduleMap), \
                      &((taskCB)->pendList), (taskCB)->priority)

#define OS_TASK_PRI_QUEUE_DEQUEUE(processCB, taskCB) \
    OsPriQueueDequeue((processCB)->threadPriQueueList, &((processCB)->threadScheduleMap), &((taskCB)->pendList))


#define OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, status) OsTaskSchedQueueEnqueue(taskCB, status)
#define OS_TASK_SCHED_QUEUE_DEQUEUE(taskCB, status) OsTaskSchedQueueDequeue(taskCB, status)

#define OS_PROCESS_PRI_QUEUE_ENQUEUE(processCB) \
    OsPriQueueEnqueue(g_priQueueList, &g_priQueueBitmap, &((processCB)->pendList), (processCB)->priority)
#define OS_PROCESS_PRI_QUEUE_ENQUEUE_HEAD(processCB) \
    OsPriQueueEnqueueHead(g_priQueueList, &g_priQueueBitmap, &((processCB)->pendList), (processCB)->priority)
#define OS_PROCESS_PRI_QUEUE_DEQUEUE(processCB) OsPriQueueProcessDequeue(&((processCB)->pendList))

#define OS_TASK_PRI_QUEUE_SIZE(processCB, taskCB) OsPriQueueSize((processCB)->threadPriQueueList, (taskCB)->priority)
#define OS_TASK_GET_NEW(processCB) LOS_DL_LIST_ENTRY(OsPriQueueTop((processCB)->threadPriQueueList,     \
                                                                    &((processCB)->threadScheduleMap)), \
                                                     LosTaskCB, pendList)

Inline function inline

Hongmeng kernel uses a lot of inline functions. What are the benefits of inline functions? If you don’t understand, check it yourself. Basic knowledge is not popularized here. Source only los_list.h , wood .c file! These inline functions, which are called the most frequently, eliminate the time and space required for popping out of the stack like ordinary functions, and are extremely efficient.

/* Define OS code data sections */
/* The indicator function is inline */
#ifndef LITE_OS_SEC_ALW_INLINE
#define LITE_OS_SEC_ALW_INLINE  /* __attribute__((always_inline)) */
#endif

LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
{
    node->pstNext = list->pstNext;
    node->pstPrev = list;
    list->pstNext->pstPrev = node;
    list->pstNext = node;
}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
{
    LOS_ListAdd(list->pstPrev, node);
}

All articles in this series enter Hongmeng system source code analysis (general catalog) view

 

 

 

Guess you like

Origin blog.csdn.net/kuangyufei/article/details/108585659