Linux kernel design and implementation-kernel data structure

main content

  • Linked list
  • queue
  • Mapping
  • Binary tree

1. Linked List

  • Singly linked list, doubly linked list
  • Circular linked list

The use of linked lists in the linux kernel is different from the linked lists defined in general data structures.
Traditional linked list:

Traditional doubly linked list.png

The biggest disadvantage of traditional linked lists is that they are not universal, because data1, data2, etc. in each node are uncertain (no matter the number or type).
The linked list in linux cleverly solves this problem. The linked list of linux does not store user data in the linked list node, but saves the linked list node in the user data.
The linux linked list node has only two pointers (pre and next). In this case, the linked list node will be independent of user data, which is convenient for the joint operation of the linked list.

Linux kernel linked list:

linux kernel doubly linked list.png

The biggest problem is how to get user data through the nodes of the linked list?
The answer is through the container_of() macro

#define container_of(ptr, type, member) ({          \
    const typeof(((type *)0)->member)*__mptr = (ptr);    \
             (type *)((char *)__mptr - offsetof(type, member)); })
  • Type is generally a structure, that is, a structure containing user data and linked list nodes.
  • ptr is a pointer to the linked list node in type
  • member is the name used to define the linked list node in type

such as:

struct student
{
    int id;
    char* name;
    struct list_head list;
};
  • type是struct student
  • ptr is a pointer to the stuct list, which is a pointer to the member type
  • member is list

Let's analyze the container_of macro:

// 步骤1:将数字0强制转型为type*,然后取得其中的member元素
((type *)0)->member  // 相当于((struct student *)0)->list

// 步骤2:定义一个临时变量__mptr,并将其也指向ptr所指向的链表节点
const typeof(((type *)0)->member)*__mptr = (ptr);

// 步骤3:计算member字段距离type中第一个字段的距离,也就是type地址和member地址之间的差
// offset(type, member)也是一个宏,定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

// 步骤4:将__mptr的地址 - type地址和member地址之间的差
// 其实也就是获取type的地址

Steps 1, 2, and 4 are relatively easy to understand. The following figure uses sturct student as an example to illustrate step 3:

  1. First, you need to know that ((TYPE *)0) means to convert address 0 to an address of type TYPE
  2. Since the address of TYPE is 0, ((TYPE *)0)->MEMBER is the difference between the address of MEMBER and the address of TYPE, as shown in the following figure:

Understanding step 3.png

2. Queue

FIFO, nothing to say

  • The size of the queue is always set to the nth power of 2 during initialization
  • Release the spinlock in the queue structure before using the queue

3. Mapping

Similar to the dictionary in python, the
hash table is a kind of mapping, but the self-balancing binary tree search tree can also store data. For example, map in C++ is a red-black tree. In the worst case, it can have better performance in the
Linux kernel. The mapping is called idr , and the goal is to map a UID located at the id identifier to a pointer

4. Red-Black Tree

5. Algorithm complexity

The big o symbol represents the upper limit (worse case) the
big θ symbol represents the minimum upper limit

At the end of the article, I will share a few video explanations of the Linux kernel:

1. The realization of the linux kernel and process scheduler, the complete fair scheduler CFS : https://www.bilibili.com/video/BV1hf4y1B7Yg/

2. Linux Kernel丨Red-Black Tree | Design Patterns and Algorithms : https://www.bilibili.com/video/BV1ig4y1v7So/

3. The Linux kernel learning video is here, so learning is easy : https://www.bilibili.com/video/BV1m54y127Mb/

Attached is a Linux kernel learning outline:

 

 

 

 

 

Guess you like

Origin blog.csdn.net/Linuxhus/article/details/111936014