内核链表

  1. 内核hlist链表
  2. 为什么pprev用二级指针

内核hlist链表

原先研究过内核的链表,也写过测试用例,但是最近做主机防护,回过头来用竟然又忘记了。这里记录一下。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "hlist.h"

typedef struct wd_maps{
    int wd;
    char *dir_name;
    char *file_name;
    struct hlist_node h_node;
}wd_maps_s;

#define WD_MAPS_SIZE (sizeof(wd_maps_s))
//#define HASH_NUM     0xFF
#define HASH_NUM     0x0F
#define MALLOC malloc

static struct hlist_head wd_tables[HASH_NUM] = {{0}};

static unsigned int hash_fun(unsigned int wd)
{
    return wd & HASH_NUM;
}

int add_wd(int wd, const char *dir_name, const char *file_name)
{
    wd_maps_s *pos = MALLOC(WD_MAPS_SIZE);
    memset(pos, 0, WD_MAPS_SIZE);


    pos->wd = wd;

    if(dir_name != NULL){
        pos->dir_name = malloc(strlen(dir_name + 1));
        strcpy(pos->dir_name, dir_name);
    }

    if(file_name != NULL){

        pos->file_name = malloc(strlen(file_name + 1));
        strcpy(pos->file_name, file_name);
    }

    hlist_add_head(&pos->h_node, &wd_tables[hash_fun(wd)]);
}

int test()
{
    int n = 20;
    int i = 0;

    // add
    for(; i < n; i++){
        char buf[1024] = {0};
        sprintf(buf, "filename = %d_.txt", i);
        add_wd(i, buf, NULL);
    }


    printf("***********************************add**********************************************************\n");
    //list 
    for(i = 0; i < HASH_NUM; i++){
        struct hlist_node *pos = NULL;
        wd_maps_s *tpos = NULL;
        hlist_for_each_entry( tpos, pos, &wd_tables[i], h_node){
            printf("%d = %s\n", tpos->wd, tpos->dir_name);
        }
    }

    // del
    for(i = 0; i < HASH_NUM; i++){

        struct hlist_node *pos, *n = NULL;

        hlist_for_each_safe(pos, n, &wd_tables[i]){
                __hlist_del(pos);
                /*注意,这里没做释放,只是在链表中删除罢了*/
        }
    }

    printf("***********************************del**********************************************************\n");

    //list 
    for(i = 0; i < HASH_NUM; i++){
        struct hlist_node *pos = NULL;
        wd_maps_s *tpos = NULL;
        hlist_for_each_entry( tpos, pos, &wd_tables[i], h_node){
            printf("%d = %s\n", tpos->wd, tpos->dir_name);
        }
    }

    printf("***********************************end**********************************************************\n");
}

int main()
{
    test();

    return 0;

}

为什么pprev用二级指针

struct hlist_head {
        struct hlist_node *first;
};

struct hlist_node {
        struct hlist_node *next;
    struct hlist_node *pprev;
};

static inline void __hlist_del(struct hlist_node *n)
{
        struct hlist_node *next = n->next;
        struct hlist_node *pprev = n->pprev;


    //问题来了 如果这里n是第一个节点,那么pprev就是NULL
    //第二个节点如何转变为第一个节点呢,无能为力,除非把头结点也传过来
        pprev->next = next;

        if (next)
                next->pprev = pprev;
}

static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
        struct hlist_node *first = h->first;
        n->next = first;
        if (first)
                first->pprev = n;
        h->first = n;

    //这里就要出问题了,ppre指向的是(struct hlist_node*)类型, 然而h的类型是 hlist_head
    //或者这里就不来设定第一个节点的pprev了
    //单单这里来说 已经可以有拒绝 *ppre的类型而改用 **ppre了,因为第一个节点的ppre是NULL的用
        n->pprev = &h->first;
}

源码点这里


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 68813175@qq.com