2007年4月13日 星期五

container_of

container_of

透過structure 的 list_head 去算structure 的start pointer

include/linux/kernel.h
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
ptr 為pointer 指向 linked-list
__mptr 為pointer 指向 linked list (和 ptr一樣, 有何差別?)

? 感覺上好像把第一行拿掉還是可以work , 然後把第二行__mptr改成 ptr, 因為第一行好像只有將 ptr assigned value 給__mptr, 其他的事情都沒有做, 另外宣告__mptr 是一個constant variable, 所已修改後的結果如下, 不過這樣改可能會出大問題, 有機會再來研究吧

#define container_of(ptr, type, member) ({ \
(type *)( (char *)ptr - offsetof(type,member) );})

其中第一行只是去做替換而已, 將 ptr 強制轉換為 __mptr variable,

1. 先把0(NULL) cast 為 (type *), 這時是一個structure pointer
2. 然後利用typeof 取其member (linked list)的type, 這時為linked list pointer
3. __mptr = (ptr) , __mptr assign value 為 ptr, 這時__mptr 還是一樣為指向 linked list pointer
4. offsetof(type,member) 會計算某一個 type (structure name) 的某一個 child member(structure field), 從structure head 到 特定的structure field (member) 之間的距離
5. (char *)__mptr, __mptr 先cast 成 char* pointer type
6. 利用__mptr 減掉 offsetof(type,member)的値, 也就是從member field 的address pointer (ex. list), 往前推(扣掉offset value), 來算出該structure (ex. struct _skypesn_) 的 address pointer value
7. 最後再把結果cast 成為 structure address pointer 即為這個list 的 "container" address, 也就是這一個macro 的名稱意義所在



const typeof( ((type *)0)->member ) *__mptr = (ptr);

Example.
net/ipv4/netfilter/ip_nat_core.c
void
ip_nat_reserved_unregister_all(struct ip_conntrack_expect *expect)
{
struct list_head *i;
struct ip_nat_reserved *res;
[omit]
i = expect->reserved_list.next;
if(i != NULL)
{
while (i != &expect->reserved_list) {
// 第一個參數 i 是指向linked_list pointer
// 第二個參數 struct ip_nat_reserved 是structure name
// 第三個參數 exp 是 structure 當中 linked list 的variable name
res = list_entry(i, struct ip_nat_reserved, exp);
[omit]

include/linux/netfilter_ipv4/ip_nat.h
/* Structure to store reserved manips */
struct ip_nat_reserved {
struct list_head hash; /* Hash chain */
struct list_head exp; /* Per-expectation list */
atomic_t use; /* Reference count */
struct ip_conntrack_manip manip; /* Reserved manip */
struct ip_conntrack_manip peer; /* Peer (optional) */
u_int16_t proto; /* Protocol number of reserved manip */
};




Reference.
include/linux/list.h
struct list_head {
struct list_head *next, *prev;
};

/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)


/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
//list_for_each_entry(tmp, &skypesns[i], list)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))

沒有留言: