본문 바로가기

Programming/Linux_Kernel

linux kernel - list 사용하기

1. struct list_head 를 갖는 struct 를 하나 선언한다.

struct A_data {

enum A_command cmd;

u8 offset;

u8 data;

struct completion complete;

bool use_completion;

int *ret;

struct list_head list;

};


2. list 를 선언한다.


/* global value */

LIST_HEAD(&A_data_list);


or


struct temp_struct {

struct  list_head B_data_list;

}




3. data 를 저장한 struct 를 list 에 넣는다.

struct A_data *A_cmd;


A_cmd = kzalloc(sizeof(struct A_data), GFP_KERNEL);

if (!A_cmd) {

pr_err("[ERROR] fail\n");

return -ENOMEM;

}

A_cmd->cmd = command;

A_cmd->offset = offset;

A_cmd->data = data;

A_cmd->use_completion = false;

  INIT_LIST_HEAD(&A_data_list);

list_add_tail(&A_cmd->list, &A_data_list);


or


struct temp_struct __temp_struct;

INIT_LIST_HEAD(&__temp_struct->B_data_list);

list_add_tail(&A_cmd->list, &__temp_struct->B_data_list);




4. 하나씩 꺼내다 쓴다.

struct A_data *data, *next;


list_for_each_entry_safe(data, next, &A_data_listlist) {

...

printk("%d", data->cmd);

}


TODO : list_for_each_entry 와 list_for_each_entry_safe 의 차이점?


5. 처리된 list 를 지우고 alloc 을 했다면 free 한다.

list_del(&data->list);

kfree(data);


list 삭제에 대해서는 추가로 아래 링크를 참고하세요.





list_entry 함수에 대해서..


동작 : 아래 list 의 point 를 가지고 todo_struct 전체를 return 해준다.


struct todo_struct {

    struct list_head list;
    int priority; /* driver specific */
    /* ... add other driver-specific fields */
};

struct list_head todo_list;

INIT_LIST_HEAD(&todo_list);



void todo_add_entry(struct todo_struct *new)

{
    struct list_head *ptr;
    struct todo_struct *entry;

    for (ptr = todo_list.next; ptr != &todo_list; ptr = ptr->next) {
        entry = list_entry(ptr, struct todo_struct, list);
        if (entry->priority < new->priority) {
            list_add_tail(&new->list, ptr);
            return;
        }
    }
    list_add_tail(&new->list, &todo_struct)
}






list_add function.


head 바로뒤에 new entry 를 붙인다.


A(head) -> B(head->next) 가 있었다면..


A(head) -> new entry(head->next) -> B(new entry->next)


가 되는 것임.



/**

 * 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.

 */

static inline void list_add(struct list_head *new, struct list_head *head)

{

__list_add(new, head, head->next);

}





list_del


A -> B -> C -> .. 

인데 list_del(B) 를 호출하면..


A.next = C;

C.prev = A;


static inline void list_del(struct list_head *entry)

{

__list_del(entry->prev, entry->next);

entry->next = (void *)0xDEADBEEF;

entry->prev = (void *)0xBEEFDEAD;

}


static inline void __list_del(struct list_head *prev, struct list_head *next)

{

next->prev = prev;

prev->next = next;

}



아래 링크에 여러 list 함수에 대한 사용 예가 잘 나와있다.

http://www.makelinux.net/ldd3/chp-11-sect-5