一文分析Linux内核klist链表

1、klist链表相关结构

内核源码中,klist相关的头文件是include/linux/klist.h,实现的文件是lib/klist.c中,接下来分析klist链表头和klist链表节点的定义:

首先是klist链表头的定义,如下:

struct klist {
    spinlock_t        k_lock;
    struct list_head    k_list;
    void            (*get)(struct klist_node *);
    void            (*put)(struct klist_node *);
} __attribute__ ((aligned (sizeof(void *))));

成员分析:

k_lock:链接节点操作所需要的自旋锁;

k_list:嵌入的双向链表list;

get:函数指针,用于链表内的节点增加引用计数;

put:函数指针,用于链表内的节点减少引用计数。

需要注意的是,该struct klist结构体是sizeof(void *)字节对齐,假如是4字节对齐的话,说明klist链表的实例地址的最低位是0,并且在klist实例中,地址的最低位具有其它用处。

接下来是klist链表中的节点结构定义,结构体名为struct klist_node,该定义如下:

struct klist_node {
    void            *n_klist;    /* never access directly */
    struct list_head    n_node;
    struct kref        n_ref;
};

成员分析:

n_klist:用于指向klist链表头;

n_node:嵌入的双向链表list;

n_ref:klist链表节点的引用计数器。

需要注意的是,n_klist指针是用来指向链表头的,它的最低位用来表示该节点是否已被请求删除,如果已经被请求删除的话,在klist链表中遍历是看不到该节点的。

这两个结构体形成的一个简单链表结构如下所示:

2、klist链表实现

接下来对klist链表的相关操作进行简单分析:

#define KLIST_INIT(_name, _get, _put)                    \
    { .k_lock    = __SPIN_LOCK_UNLOCKED(_name.k_lock),        \
      .k_list    = LIST_HEAD_INIT(_name.k_list),            \
      .get        = _get,                        \
      .put        = _put, }

#define DEFINE_KLIST(_name, _get, _put)                    \
    struct klist _name = KLIST_INIT(_name, _get, _put)

/**
 * klist_init - Initialize a klist structure.
 * @k: The klist we're initializing.
 * @get: The get function for the embedding object (NULL if none)
 * @put: The put function for the embedding object (NULL if none)
 *
 * Initialises the klist structure.  If the klist_node structures are
 * going to be embedded in refcounted objects (necessary for safe
 * deletion) then the get/put arguments are used to initialise
 * functions that take and release references on the embedding
 * objects.
 */
void klist_init(struct klist *k, void (*get)(struct klist_node *),
        void (*put)(struct klist_node *))
{
    INIT_LIST_HEAD(&k->k_list); //双向链表初始化
    spin_lock_init(&k->k_lock); //自旋锁初始化
    k->get = get;
    k->put = put;
}

KLIST_INIT()宏用于对klist的链表头进行初始化,包括自旋锁以及嵌入的双向链表初始化,DEFINE_KLIST()宏则是用来定义一个klist,并调用KLIST_INIT()宏进行初始化,klist_init()则是使用函数的方式对klist进行初始化。

/*
 * Use the lowest bit of n_klist to mark deleted nodes and exclude
 * dead ones from iteration.
 */
#define KNODE_DEAD        1LU
#define KNODE_KLIST_MASK    ~KNODE_DEAD

static struct klist *knode_klist(struct klist_node *knode)
{
    return (struct klist *)
        ((unsigned long)knode->n_klist & KNODE_KLIST_MASK);//将指针的最低位清0,并返回指针
}

static bool knode_dead(struct klist_node *knode)
{
    return (unsigned long)knode->n_klist & KNODE_DEAD;//判断最低位
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值