内核链表及应用


1.内核链表的定义
1)下面是链表结构体定义,由定义可知为双向链表
2)通过链表命名可知该链表没有头结节(链表头),没有头节点意味着每一也都是头节点。
3)由于没有头节点,该链表又实现循环链表功能。
struct list_head {
        struct list_head *next, *prev;
};


2.链表初始化
链表使用首先要初始化,下面初始化代码。
static inline void INIT_LIST_HEAD(struct list_head *list)
{
        list->next = list;
        list->prev = list;
}

3.链表的添加
1).链表的添加分为两种,一种头部添加,另一种尾部添加。
2).list_add函数实现头部插入节点, 所以参数至少具有两个参数一个插入节点,一个是头部。
3).头部添加实现栈的功能(先进后出), 尾部插入实现是队列功能(先进先出)。
static inline void list_add(struct list_head *new, struct list_head *head)
{
        __list_add(new, head, head->next);
}
static inline void __list_add(struct list_head *new,
                              struct list_head *prev,
                              struct list_head *next)
{
        next->prev = new;
        new->next = next;
        new->prev = prev;
        prev->next = new;
}

4.链表的删除
1).list_del函数实现节点删除,由于是双向链表,所以节点删除函数一个参数足以,即删除节点。
2).注意此函数只是删除该节点,并不释放内存。
static inline void list_del(struct list_head *entry)
{
        __list_del(entry->prev, entry->next);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
}

static inline void __list_del(struct list_head * prev, struct list_head * next)
{
        next->prev = prev;
        prev->next = next;
}

5.获取包含list_head结构体的元素
1).获取包含list_head结构体的元素
#define list_entry(ptr, type, member) \
        container_of(ptr, type, member)
#define list_entry(ptr, type, member) \
        container_of(ptr, type, member)
2).寻找包含者,首先知道包含者大小,另外被包含者名称,被被包含者所处位置。 所以下面函数实际包含三个参数。
ptr:被包含者所处位置
member:被包含者名称
type:包含者大小
#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})


6.链表应用举例----等待队列
1)队列初始化
#define init_waitqueue_head(q)                          \
        do {                                            \
                static struct lock_class_key __key;     \
                                                        \
                __init_waitqueue_head((q), &__key);     \
        } while (0)


void __init_waitqueue_head(wait_queue_head_t *q, struct lock_class_key *key)
{
        spin_lock_init(&q->lock);
        lockdep_set_class(&q->lock, key);
        INIT_LIST_HEAD(&q->task_list);
}

2)队列入队操作
1)可能要问队列的入队操作为先进先出,应该采用list_add_tail函数。因为使用add_wait_queue函数时,不需要完全队列操作。
2)然而也提够__add_wait_queue_tail函数,该函数实现真正队列操作(先进先出)。

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;

        wait->flags &= ~WQ_FLAG_EXCLUSIVE;
        spin_lock_irqsave(&q->lock, flags);
        __add_wait_queue(q, wait);
        spin_unlock_irqrestore(&q->lock, flags);
}
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
        list_add(&new->task_list, &head->task_list);
}

3)队列出队操作
1)可能要问上面不是说删除一个参数就够了,为什么这里两个?主要原因链表属于共享数据,需要加锁保护,而这个锁保护整个链表。
2)顺便分析一下这个锁spin_lock_irqsave,
此锁为自旋锁,自旋锁目的是保护多处理器对数据访问与操作。
另外此锁需关闭中断,意味可能某处中断处理程序也会操作该结构。
最后保存中断状态,解锁时候恢复中断状态。

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
        unsigned long flags;

        spin_lock_irqsave(&q->lock, flags);
        __remove_wait_queue(q, wait);
        spin_unlock_irqrestore(&q->lock, flags);
}
static inline void __remove_wait_queue(wait_queue_head_t *head,
                                                        wait_queue_t *old)
{       
        list_del(&old->task_list);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值