链表存在以下几种形式
- 单向
- 双向(doubly)
- 线性(linear)
- 循环(circular)
- 有头
- 无头(without header node)
Linux Kernel include/linux/list.h
a linear list
list --> [info | next] --> [info | next] --> [info | next] --> [info | NULL]
a circular list with header node
Header Node First Node Last Node
--> [NULL | next] --> [info | next] --> [info | next] --> [info | next] --> [info | next]--+
| |
+------------------------------------------------------------------------------------------+
with or without header node
主要区别在于双向链表的结构体设计,是否需要存在一个不带有有效负载,只有链表控制信息的头节点,例如:
with header node
struct gxlist_head
{
struct gxlist_head *next, *prev;
};
struct _hot_device {
int id;
int active;
GxFsActionType action;
struct gxlist_head head;
int hot;
GxHotplugError error;
void *priv;
};
#define GX_LIST_HEAD_INIT(name) { &(name), &(name) }
#define GX_LIST_HEAD(name) \
struct gxlist_head name = GX_LIST_HEAD_INIT(name)
GX_LIST_HEAD(__device_list); //双向循环链表的头节点,整个链表通过这个节点进行管理
struct _hot_device *dev = NULL;
gxlist_add(&dev->head, &__device_list);
without header node
struct gxlist_head
{
struct gxlist_head *next, *prev;
};
struct _hot_device {
int id;
int active;
GxFsActionType action;
struct gxlist_head head;
int hot;
GxHotplugError error;
void *priv;
};
#define GX_LIST_HEAD_INIT(name) { &(name), &(name) }
#define GX_LIST_HEAD(name) struct gxlist_head name = GX_LIST_HEAD_INIT(name)
有头双向循环链表
无头双向循环链表
source code
链表的设计,next 和 priv 可以指向数据节点也可以指向控制节点,以下代码设计即指向控制节点
struct gxlist_head
{
struct gxlist_head *next, *prev;
};
//双向链表初始化,next和prev均指向链表header
#define GX_LIST_HEAD_INIT(name) { &(name), &(name) }
//声明双向链表Header Node
#define GX_LIST_HEAD(name) struct gxlist_head name = GX_LIST_HEAD_INIT(name)
#define GX_INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
void gxlist_add (struct gxlist_head *newnode, struct gxlist_head *head);
void gxlist_add_tail(struct gxlist_head *newnode, struct gxlist_head *head);
void gxlist_del (struct gxlist_head *entry);
void gxlist_del_init(struct gxlist_head *entry);
int gxlist_empty (struct gxlist_head *head );
void gxlist_splice (struct gxlist_head *list, struct gxlist_head *head);
struct gxlist_head *gxlist_get(struct gxlist_head *head);
//根据控制成员(member)偏移量来获取数据节点地址
#define gxlist_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
//从双向链表中循环取出链表控制信息段(struct gxlist_head)
//从双向链表中循环取出pos,pos类型为 struct gxlist_head
#define gxlist_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)
//从双向链表中根据member循环取出数据节点
//从双向链表中取出pos,pos类型为包含member成员的结构体
#define gxlist_for_each_entry(pos, head, member) \
for (pos = gxlist_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = gxlist_entry(pos->member.next, typeof(*pos), member))
//反序
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
//从数据节点中直接取出双向循环链表
#define list_from_node(pos, node, member, head) \
for (pos = list_entry((node)->next, typeof(*pos), member); \
pos != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
//反序从数据节点中直接取出双向循环链表
#define list_from_node_reverse(pos, node, member, head) \
for (pos = list_entry((node)->prev, typeof(*pos), member); \
pos != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
//safe系列接口,n与pos相同的数据类型,n为链表中pos的下一个
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
#endif
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static void __list_add(struct gxlist_head *new_node, struct gxlist_head *head, struct gxlist_head *head_next)
{
head_next->prev = new_node;
new_node->next = head_next;
new_node->prev = head;
head->next = new_node;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
void gxlist_add(struct gxlist_head *new_node, struct gxlist_head *head)
{
__list_add(new_node, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
void gxlist_add_tail(struct gxlist_head *new_node, struct gxlist_head *head)
{
__list_add(new_node, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static void __list_del(struct gxlist_head *prev_head, struct gxlist_head *next_head)
{
next_head->prev = prev_head;
prev_head->next = next_head;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
void gxlist_del(struct gxlist_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
void gxlist_del_init(struct gxlist_head *entry)
{
__list_del(entry->prev, entry->next);
GX_INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
int gxlist_empty(struct gxlist_head *head)
{
return head->next == head;
}
struct gxlist_head *gxlist_get(struct gxlist_head *head)
{
struct gxlist_head *first = head->next;
if (first != head) {
__list_del(first->prev, first->next);
return first;
}
return 0;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
void gxlist_splice(struct gxlist_head *list, struct gxlist_head *head)
{
//去除header node
struct gxlist_head *first = list->next;
if (first != list) {
struct gxlist_head *last = list->prev;
struct gxlist_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
GX_LIST_HEAD(__usbwifi_device_list);
cyg_mutex_t usbwifi_list_lock;
#define DEV_LOCK() cyg_mutex_lock(&usbwifi_list_lock)
#define DEV_UNLOCK() cyg_mutex_unlock(&usbwifi_list_lock)
#define DEV_TRYLOCK() cyg_mutex_trylock(&usbwifi_list_lock)
void (*proc_wifi_init)(void);
void (*proc_wifi_exit)(void);
static void usbwifi_proc(void *p)
{
usbwifi_dev_info disk_info;
struct gx_usbwifi_hot_device *dev = NULL;
while(1) {
if (0 != usbwifi_detect(&disk_info)) {
LOG("disk_detect return error \n");
continue;
}
if (disk_info.dev_status == CYG_IO_SET_CONFIG_DISK_IN) {
dev = GxCore_Malloc(sizeof(struct gx_usbwifi_hot_device));
if (NULL == dev) {
printf(" %s cann't fetch memory, try again \n", __func__);
continue;
}
memset(dev, 0, sizeof(struct gx_usbwifi_hot_device));
dev->id = disk_info.index;
dev->hot = 0;
dev->active = 1;
dev->action = PLUG_IN;
dev->error = PLUG_SUCCESS;
DEV_LOCK();
gxlist_add(&dev->head, &__usbwifi_device_list);
DEV_UNLOCK();
cyg_semaphore_post(&device_detect_sem);
if (proc_wifi_init)
(*proc_wifi_init)();
}
else if (disk_info.dev_status == CYG_IO_SET_CONFIG_DISK_OUT) {
int found = 0;
DEV_LOCK();
gxlist_for_each_entry(dev, &__usbwifi_device_list, head) {
if (dev->id == disk_info.index) {
found = 1;
break;
}
}
if (found == 0) {
DEV_UNLOCK();
continue;
}
dev->action = PLUG_OUT;
DEV_UNLOCK();
cyg_semaphore_post(&device_detect_sem);
if (proc_wifi_exit)
(*proc_wifi_exit)();
}
GxCore_ThreadDelay(20);
}
}
void GxCore_UsbwifiHotplugInit()
{
handle_t thread_id_do;
cyg_semaphore_init(&device_detect_sem, 0);
cyg_mutex_init(&usbwifi_list_lock);
LOG("device_detect_sem.count = 0x%x , line = %d \n", device_detect_sem.count, __LINE__);
GxCore_ThreadCreate(
"usbwifi_proc",
&thread_id_do,
usbwifi_proc,
NULL,
8 * 1024,
GXOS_DEFAULT_PRIORITY);
}
struct gx_usbwifi_hot_device *GxCore_UsbwifiHotplugGetFirst(void)
{
if (gxlist_empty(&__usbwifi_device_list) )
return NULL;
return gxlist_entry(__usbwifi_device_list.next, struct gx_usbwifi_hot_device, head);
}
struct gx_usbwifi_hot_device *GxCore_UsbwifiHotplugGetNext(struct gx_usbwifi_hot_device *dev)
{
if (dev == NULL)
return NULL;
if (dev->head.next == &__usbwifi_device_list)
return NULL;
return gxlist_entry(dev->head.next, struct gx_usbwifi_hot_device, head);
}
struct gx_usbwifi_hot_device *GxCore_UsbwifiHotplugWait(void)
{
cyg_semaphore_wait(&device_detect_sem);
DEV_LOCK();
if (gxlist_empty(&__usbwifi_device_list) ) {
return NULL;
}
return gxlist_entry(__usbwifi_device_list.next, struct gx_usbwifi_hot_device, head);
}
int GxCore_UsbwifiHotplugClean(void)
{
struct gx_usbwifi_hot_device *dev, *n;
gxlist_for_each_entry_safe(dev, n, &__usbwifi_device_list, head) {
if (dev->action == PLUG_OUT) {
gxlist_del(&dev->head);
GxCore_Free(dev);
}
}
DEV_UNLOCK();
return GXCORE_SUCCESS;
}
typedef enum {
PLUG_IN = 1,
PLUG_OUT = 2,
PLUG_CLEAN = 3,
}GxFsActionType;
typedef enum {
PLUG_SUCCESS = 0,
PLUG_ERROR_FS_NO_SUPPORT = 1,
PLUG_ERROR_NO_PARTITION = 2,
} GxHotplugError;
struct gx_usbwifi_hot_device {
int id;
int active;
GxFsActionType action; // PLUG-IN PLUG-OUT
struct gxlist_head head;
int hot;
GxHotplugError error;
void *priv;
};