第6章 內(nèi)核數(shù)據(jù)結(jié)構(gòu)

Linux內(nèi)核實現(xiàn)了常用的通用數(shù)據(jù)結(jié)構(gòu):

  • 鏈表
  • 隊列
  • 映射
  • 二叉樹
    內(nèi)核開發(fā)者應(yīng)盡可能使用這些數(shù)據(jù)結(jié)構(gòu),不要造輪子重復(fù)開發(fā)。

一、鏈表

鏈表數(shù)據(jù)結(jié)構(gòu):

//<linux/list.h>
struct list_head {
    struct list_head *next;
    struct list_head *prev;
};

因為C語言中,一個給定結(jié)構(gòu)的變量偏移在編譯時地址就被ABI固定下來了,所有使用宏container_of()可以從鏈表指針找到父結(jié)構(gòu)中包含的任何變量:

#define container_of(ptr, type, member) ({\
    const typeof( ( (type *)0)->member ) *__mptr = (ptr); \
    (type *)( (char *)__mptr - offsetof(type,member) ); })

返回包含list_head的父類型結(jié)構(gòu)體:

#define list_entry(ptr, type, member) container_of(ptr, type, member)

初始化鏈表:

INIT_LIST_HEAD(struct list_head*);

鏈表頭:

static LIST_HEAD(struct list_head*)

增加鏈表節(jié)點:

list_add(struct list_head *new, struct list_head *head)
list_add_tail(struct list_head *new, struct list_head *head)

刪除鏈表節(jié)點:

list_del(struct list_head *entry)
list_del_init(struct list_head *entry)

遍歷鏈表:

list_for_each(struct list_head *p, struct list_head *head) //p依次指向head為頭節(jié)點的鏈表中的節(jié)點

list_for_each_entry(typeof(member) *f, struct list_head *head, member) //f依次指向head為頭節(jié)點的鏈表中的節(jié)點的父結(jié)構(gòu)中member成員

二、隊列

Linux內(nèi)核通用隊列實現(xiàn)稱為kfifo。

初始化隊列:

int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask);
int kfifo_init(struct kfifo *fifo, void *bufffer, unsigned int size);

// size必須是2的冪

推入隊列數(shù)據(jù):

unsigned int kfifo_in(struct kfifo *fifo, const void *from, unsigned int len);

摘取隊列數(shù)據(jù):

unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len);
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, unsigned offset);  //只讀取不從隊列中刪除數(shù)據(jù)

獲取隊列長度:

static inline unsigned int kfifo_size(struct kfifo *fifo); //隊列空間總體大小
static inline unsigned int kfifo_len(struct kfifo *fifo); //已推入數(shù)據(jù)大小
static inline unsigned int kfifo_avail(struct kfifo *fifo); //隊列中還有多少可用空間
static inline int kfifo_is_empty(struct kfifo *fifo); //隊列是否空
static inline int kfifo_is_full(struct kfifo *fifo); //隊列是否滿

重置隊列:

static inline void kfifo_reset(struct kfifo *fifo);

撤銷隊列:

void kfifo_free(struct kfifo *fifo);

三、映射

Linux內(nèi)核提供了簡單、有效的映射數(shù)據(jù)結(jié)構(gòu),目標(biāo)是:映射一個唯一的標(biāo)識數(shù)(UID)到一個指針。idr數(shù)據(jù)結(jié)構(gòu)用于映射用戶空間的UID。

初始化idr:

void  idr_init(struct idr *idp);

分配新的UID,分為兩步:

  • 1、告訴idr需要分配新的UID,允許其在必要時調(diào)整后備樹的大小
int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
  • 2、獲取新的UID,并且將其加到idr:
int idr_get_new(struct idr *idp, void *ptr, int *id);
int idr_get_new_above(struct idr *idp, void *ptr, int startint_id, int *id); //分配的UID必須大于或等于startint_id

查找UID:

void *idr_find(strcut idr *idp, int, id);

刪除UID:

void idr_remove(struct idr *idp, int id);

撤銷idr:

void idr_destroy(struct idr *idp); //只釋放idr中未使用的內(nèi)存,不釋放當(dāng)前分配給UID使用的任何內(nèi)存
void idr_remove_all(struct idr *idp); //刪除所有UID

四、二叉樹

Linux實現(xiàn)的紅黑樹稱為rbtree。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容