linux list_head


原文链接: linux list_head

https://blog.csdn.net/wanshilun/article/details/79747710

xxx_init() 用来对一个数据结果对象赋初始值
init_xxx 初始化一个对象

一起分析内核最重要的链表list_head

一、链表结构

struct list_head {
	struct list_head *next, *prev;
};

二、链表初始化函数

list_head 链表的初始化只是把 *next, *prev连个指针指向链表头,形成双向循环链表;

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)

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

上面是各种不同的初始化或者定义并初始化链表的函数,我们都可以使用,
例如:
1)我们自己定义一个链表头,然后调用函数初始化:

struct list_head name = LIST_HEAD_INIT(name);
// INIT_LIST_HEAD(name);

2)或者使用下面宏定义并初始化一个双向循环链表头;

LIST_HEAD(name)

三、增、删、遍历接口

我们都知道链表是用来保存一下有意义的字段的,但是list_haed结构中并没有其他字段,所以内核使用该链表时,总是把它嵌套到一个宿主结构中来使用。例如:

struct  my_list{
    struct list_head mylist;
    int val ;
};

3.1 增加节点

内核中提供了添加一个节点的接口,如下:

static inline void list_add(struct list_head *new, struct list_head *head);//首插入
static inline void list_add_tail(struct list_head *new, struct list_head *head);//尾插入

3.2 删除节点

static inline void list_del(struct list_head *entry)

3.3 遍历链表

内核是同过下面这个宏定义来完成对list_head链表进行遍历的,如下 :

#define list_for_each(pos, head)  for (pos = (head)->next; pos != (head); pos = pos->next`) //从前往后
#define list_for_each_prev(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev) //从后往前

3.4 定位宿主

上面的所有操作都是基于list_head这个链表进行的,涉及的结构体也都是该结构体,但是我们知道,这个结构体是嵌入到别的宿主中使用的,所以我们应该定位到该结构体的宿主位置,内核中有定义宏去直接得到宿主的地址,如下:
作用:已知某结构体的成员member和指向该成员的指针ptr(也就是member的地址),算出该结构体的起始地址。

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

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)

我们分析上面这个宏,发现有好些都不认识,这里一个一个分析:
( (TYPE *)0 ) 将零转型为TYPE类型指针;
((TYPE *)0)->MEMBER 访问结构中的数据成员;
&( ( (TYPE _)0 )->MEMBER )取出数据成员的地址;,因为是从0开始的,所以就相当于该成员在结构体中的偏移量。
(sizet)(&(((TYPE)0)->MEMBER))结果转换类型;
typeof为C语言的关键字,用来由变量得到变量的类型,eg;typeof(a)得到变量a的类型。

经过上面分析可以看出来,其实现就是通过mem成员的地址减去mem的偏移量,来得到首地址,即宿主的地址。

3.5 宿主结构的遍历

宿主结构的遍历,它们的实现都是利用list_entry宏。

#define list_entry((ptr)->next, type, member)  	container_of(ptr,type,member)
#define list_for_each_entry(pos, head, member)                \
    for (pos = list_entry((head)->next, typeof(*pos), member);    \
         &pos->member != (head);     \
         pos = list_entry(pos->member.next, typeof(*pos), member))
#include "list.h" /*由于我的机器上没有list.h,所以我拷贝了一个,如果你机器上有,应该是加#include <linux/list.h>*/
#include <stdio.h> 
#include <string.h>

#define MAX_USER_LEN 32
#define MAX_PAS_LEN 32
#define MAX_SERVER_LEN 1024


typedef struct server_detect_ftp
{
	struct list_head list;
	char server[MAX_SERVER_LEN];
	int port;
	char username[MAX_USER_LEN];
	char password[MAX_PAS_LEN];
}server_detect_ftp_t;

int main(void)
{
	struct list_head head;//头部
	server_detect_ftp_t ftp_link;
	server_detect_ftp_t ftp_link1;
	server_detect_ftp_t *entry;
	struct list_head *p;
	INIT_LIST_HEAD(&head);//初始化头部
	strcpy(ftp_link.server,"www.163.com");
	ftp_link.port=34;
	strcpy(ftp_link.username,"good");
	strcpy(ftp_link.password,"good");

	strcpy(ftp_link1.server,"www.163.com");
	ftp_link1.port=34;
	strcpy(ftp_link1.username,"good");
	strcpy(ftp_link1.password,"good");

	INIT_LIST_HEAD(&head);

	list_add(&ftp_link.list,&head);
	list_add(&ftp_link1.list,&head);//添加链表
	list_del(&ftp_link1.list);//删除链表
	list_for_each(p,&head)//遍历
	{
		entry=list_entry(p,struct server_detect_ftp,list);//读取某个值

		printf("%s\n",entry->username);
	}

	return 0;
}



#include "list.h"
#include "time.h"
struct rtc_alarm_dev
{
    time_t expect;
    int repeat;
    volatile int interval;
    void *(*func)(void *);
    struct list_head list;
} rtc_alarm_dev_t;

struct list_head rtc_alarm_list;
// #define _DEBUG

int rtc_alarm_isActive(struct rtc_alarm_dev *timer);

int rtc_alarm_add(struct rtc_alarm_dev *timer)
{
    struct list_head *plist;
    struct rtc_alarm_dev *dev;

    if (rtc_alarm_isActive(timer))
        rtc_alarm_del(timer);

    if (list_empty(&rtc_alarm_list))
    {
        list_add(&timer->list, &rtc_alarm_list);
    }
    else
    {
        list_for_each(plist, &rtc_alarm_list)
        {
            dev = list_entry(plist, struct rtc_alarm_dev, list);
            if (dev->expect > timer->expect)
            {
                list_add(&timer->list, dev->list.prev);
                break;
            }
        }
        if (plist == &rtc_alarm_list)
            list_add(&timer->list, &dev->list);
    }

#ifdef _DEBUG
    list_for_each(plist, &rtc_alarm_list)
    {
        printf("%s debug: dev->expect = %d, dev = %08x list: %p %p\n", __func__, dev->expect, dev, plist, rtc_alarm_list);

        dev = list_entry(plist, struct rtc_alarm_dev, list);
        printf("%s debug: dev->expect = %d, dev = %08x list: %p\n", __func__, dev->expect, dev, plist);
    }
    // printf("%s debug: dev->expect = %d, dev = %08x list: %p\n", __func__, dev->expect, dev,plist);

#endif

    //	rtc_alarm_update();

    return 0;
}

int rtc_alarm_isActive(struct rtc_alarm_dev *timer)
{
    struct list_head *plist;
    struct rtc_alarm_dev *dev;
    int active = 0;

    list_for_each(plist, &rtc_alarm_list)
    {
        dev = list_entry(plist, struct rtc_alarm_dev, list);
        if (dev == timer)
        {
            active = 1;
            break;
        }
    }

    return active;
}

int rtc_alarm_del(struct rtc_alarm_dev *timer)
{
    struct list_head *plist;
    struct rtc_alarm_dev *dev;
    list_for_each(plist, &rtc_alarm_list)
    {
        dev = list_entry(plist, struct rtc_alarm_dev, list);
        if (dev == timer)
        {
            plist = plist->prev;
            list_del(&dev->list);
            break;
        }
    }
    return 0;
}

int main()
{

    INIT_LIST_HEAD(&rtc_alarm_list);
    struct rtc_alarm_dev sample_dev_1;
    memset(&sample_dev_1, 0, sizeof(struct rtc_alarm_dev));
    sample_dev_1.func = NULL;
    sample_dev_1.repeat = 1;
    sample_dev_1.interval = 1 * 60; /* Sampling Cycle */
    // now = rtc_get_time();
    // tm = gmtime(&now);
    // expect = now - tm->tm_sec + (2 - tm->tm_min % 2) * 60;
    //	expect = now + 10;
    // tm = gmtime(&expect);
    // logcat("TGQingXie Expect: %s", asctime(tm));
    sample_dev_1.expect = 10;
    rtc_alarm_add(&sample_dev_1);
    struct rtc_alarm_dev sample_dev_2;

    sample_dev_2.expect = 15;

    rtc_alarm_add(&sample_dev_2);

    struct list_head *plist;
    struct rtc_alarm_dev *dev;

    list_for_each(plist, &rtc_alarm_list)
    {

        dev = list_entry(plist, struct rtc_alarm_dev, list);
        printf("%s debug: dev->expect = %d, dev = %08x list: %p %p\n", __func__, dev->expect, dev, plist, &rtc_alarm_list);
    }
    printf("%s debug: dev->expect = %d, dev = %08x list: %p %p\n", __func__, dev->expect, dev, plist, &rtc_alarm_list);

    // main debug: dev->expect = 10, dev = e439c2b0 list: 0x7ffee439c2c8 0x10b864040
    // main debug: dev->expect = 15, dev = e439c288 list: 0x7ffee439c2a0 0x10b864040
    // main debug: dev->expect = 15, dev = e439c288 list: 0x10b864040 0x10b864040
}
`