美文网首页
Kernel List API

Kernel List API

作者: wyann | 来源:发表于2018-11-23 06:42 被阅读0次

    In Linux Kernel source code, its common to find lots of manipulations related to List, like the double link list of the process descriptor. It's necessary to figure out those List APIs.

    List Struct

    We use struct list_head to represent the list data structure.

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

    This implementation make sure that we can get the list->next and list->prev(double linked),and every element in the list is list_head type.

    List Macro

    Also we need to iterate elements in the list. Linux define list_for_each as a macro.

    #define list_for_each(pos,head)\
        for(pos=head->next;pos!=head;pos=pos->next)
    

    list_head actually is like a address identifier of its container, which means that list_head can only indicates the current location of its container, but doesn't have any value. So how can we get its container. Linux give the solution below.

    #define list_entry(ptr, type, member) \ 
        container_of(ptr, type, member) 
    #define container_of(ptr, type, member) ({                      
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    
        (type *)( (char *)__mptr - offsetof(type,member) );
    })
    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    

    list_entry actually is identical to container_of ,which is used to calculate the container address position of ptr
    The second param type is the type if container
    The last param *member is the name of ptr in the container field.
    offsetof(type,member) is aimed to calculate the offset from base address of type to the address of member.Its implementation is a little tricky since it cast 0 to the type of type. The address of 0 actually is the base address of struct. Followed by pointed to member, the result is the address offset of the member in type exactly.
    Then we cast ptr to char* to make sure that the unit distance of address of ptr is one byte. Finally we use address of ptr minus offset and the result is the address of container. All done!

    Application

    With the API implemented above, we can realize the function like iterate all the children of current process as below.

    list_for_each(list, &current->children) {
      task = list_entry(list, struct task_struct, sibling);
      /* task now points to one of current’s children */
    }
    

    People may get confused about the third param of list_entry, sibling. The figure below can explain that.

    aaa.jpg
    We also can get the next or previous task,use
    list_entry(task->tasks.next, struct task_struct, tasks)
    list_entry(task->tasks.prev, struct task_struct, tasks)
    

    相关文章

      网友评论

          本文标题:Kernel List API

          本文链接:https://www.haomeiwen.com/subject/ziddqqtx.html