Zephyr OS All the learning notes that have been hosted on the GITHUB,CSDN blog are just copies of the content on Github, so the link will be wrong, please understand.
please visit github:https://github.com/tidyjiang8/zephyr-inside for the latest study notes.
In this paper, we briefly introduce some of the knowledge of inline functions, and then analyze the source code of the linked list in the Zephyr OS kernel in detail. The initialization of a chain list of inline function lists determines whether a node is the head node of a linked list, determines whether a node is the tail node of a linked list, determines whether a linked list is empty. Gets the chain table head node gets the next node of the node at the end of the list Insert node at the end of the list insert node after a node is inserted Node deletes a node out of the first node inline (inline) function
In the Zephyr OS, a doubly linked list is implemented with the code in the header file inclue/misc/dlist.h.
Actually the function is implemented in the header file. In a closer look, these functions are not normal functions, but inline functions.
Why. What good is this? A search on the Internet, summarized as follows: What is an inline function:
In short, inline functions are functions that are modified with the keyword inline. When the compiler compiles a file that contains an inline function, it expands the function where the inline function is called, similar to the process of working with the macro. However, when an inline function is expanded, the compiler checks the type of the inline function, such as checking parameters, returning value types, and so on. When to use inline functions:
If a piece of code needs to be reused, and the frequency of reuse is high and the code is short, inline functions are recommended. Inline Functions vs Macros:
The compiler will type-check the inline function and simply replace the macro. The inline function is expanded at compile time, and the macro is expanded during precompilation with inline functions vs common functions:
As already mentioned, the invocation frequency of the inline function is high, the code is short, in this case, if the use of the normal function without an inline function, it will reduce the operational efficiency, because the function calls have overhead, such as parameters, return value, return address, such as the stack, the stack operation. Disadvantages of inline functions:
Increased the size of the compiled code.
In the Zephyr OS source code, you will also see another set of linked lists, located in Net/ip/contiki/os/list. [CH]. This list is ported to Contiki and is only used in the IP protocol stack. definition of a linked list
struct _dnode {
union {
struct _dnode *head;
struct _dnode *next;
};
Union {
struct _dnode *tail;
struct _dnode *prev;
};
};
The first eye is blindfolded, why the definition of the node there are actually two of the consortium. Until I saw it, I thought of myself. There are two types of tpyedef defined in the Zephyr OS using the struct:
typedef struct _DNODE sys_dlist_t;
typedef struct _DNODE sys_dnode_t;
sys_dlist_t defines a doubly linked list, and sys_dnode_t defines a node. When using sys_dlist_t, the head in the struct is used, tail two members, and when using sys_dnode_t, the next in the struct is used, prev two idioms.
In fact, we can expand the above code into two structures:
typedef struct _DNODE {//define node
struct _dnode *next; Successor node
struct _donde *prev; Precursor node
} sys_dnode_t;
typedef struct _DLIST {// define linked list
struct _dlist *head; chain head
struct _dlist *tail; chain footer
} sys_dlist_t;
Someone may be confused by the two concepts of linked lists and nodes, like the one I used to be. We just have to remember that when we use a linked list, we define a list and then add nodes to the list, delete nodes, find nodes, and so on. Like what:
sys_dlist_t MyList; Define Chain list
sys_dlist_init (&mylist); Linked list initialization
sys_dnode_t mynode1, mynode2;//Definition node ... Initialize the node to
sys_dlist_append (&mylist, &mynode1); Insert Node 1
sys_dlist_append (&mylist, &mynode2); Inserting nodes 2
the initialization of a linked list
static inline void Sys_dlist_init (sys_dlist_t *list)
{
List->head = (sys_dnode_t *) list;
List->tail = (sys_dnode_t *) list;
}
Understand the above mentioned things, and then see the specific code implementation, so easy.
When the list is initialized, the list is empty and there are no nodes, so head, tail, two pointers point to the list itself. determine if a node is the head node of a linked list
static inline int Sys_dlist_is_head (sys_dlist_t *list, sys_dnode_t *node)
{
return list->head = = node;
}
determine if a node is a tail node of a linked list
static inline int Sys_dlist_is_tail (sys_dlist_t *list, sys_dnode_t *node)
{
return list->tail = = node;
}
determine if the linked list is empty
static inline int sys_dlist_is_empty (sys_dlist_t *list)
{
return list->head = = list;
}
get the link header node
Static inline sys_dnode_t *sys_dlist_peek_head (sys_dlist_t *list)
{
return sys_dlist_is_empty (list)? null:list->head;
}
Determines whether the linked list is empty, returns null if it is empty, or returns the head node. Therefore, when you use the function, you need to determine whether the return value is NULL, and then do the processing. gets the next node of the node
Static inline sys_dnode_t *sys_dlist_peek_next (sys_dlist_t *list,
sys_dnode_t *node)
{
return node = = List->tail? null:node->next;
}
The first is whether the incoming node is the tail node of the list, or NULL if it is, otherwise the next node is returned. Therefore, when you use the function, you need to determine whether the return value is NULL, and then do the processing. inserting nodes at the end of a linked list
static inline void Sys_dlist_append (sys_dlist_t *list, sys_dnode_t *node)
{
node->next = list;
Node->prev = list->tail;
list->tail->next = node;
list->tail = node;
}
inserting nodes in a linked list header
static inline void Sys_dlist_prepend (sys_dlist_t *list, sys_dnode_t *node)
{
Node->next = list->head;
Node->prev = list;
List->head->prev = node;
list->head = node;
}
to insert a node after a node
static inline void Sys_dlist_insert_after (sys_dlist_t *list,
sys_dnode_t *insert_point, sys_dnode_t *node)
{
if (!insert_point) {
sys_dlist_prepend (list, node);
} else {
Node->next = insert_point-> Next;
Node->prev = Insert_point;
Insert_point->next->prev = node;
insert_point->next = node;
}
}
to insert a node before a node
static inline void Sys_dlist_insert_before (sys_dlist_t *list,
sys_dnode_t *insert_point, sys_dnode_t *node)
{
if (!insert_point) {
sys_dlist_append (list, node);
} else {
Node->prev = insert_point->prev;
Node->next = Insert_point;
insert_point->prev->next = node;
Insert_point->prev = node;
}
}
Delete a node
static inline void Sys_dlist_remove (sys_dnode_t *node)
{
Node->prev->next = node->next;
Node->next->prev = node->prev;
}
Remove the first node
Static inline sys_dnode_t *sys_dlist_get (sys_dlist_t *list)
{
sys_dnode_t *node;
if (Sys_dlist_is_empty (list)) {
return NULL;
}
node = list->head;
Sys_dlist_remove (node);
return node;
}
Remove the head node after it has been removed from its re-linked list.