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
}