In Linux kernel, it is common to use a C structure to represent a hardware or software object. However, when the object is passed as an argument to a function, it is usually necessary to access data from other parts of the same structure. To solve this problem, Linux provides the “container_of” macro to obtain a pointer to the top level structure containing the given pointer. In this article, we will discuss the efficient use of “container_of” macro and explain its usage with some examples.
The “container_of” macro has the following definition:
```
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type, member) ); })
```
It takes three arguments:
- ptr: A pointer to a member within a structure.
- type: The name of the structure that contains the member.
- member: The name of the member within the structure pointed to by ptr.
The macro returns a pointer to the top level structure (of type “type”) that contains the member “member” pointed to by “ptr”.
Now that we have understood the syntax of the “container_of” macro, let us discuss some efficient ways of using it:
1. Error checking before invoking the macro
Before invoking the “container_of” macro, it is important to check if the pointer passed as an argument is not null. This is because the macro derefences the pointer passed to it, which could lead to a segmentation fault if the pointer is null. It is also important to check if the “member” argument is indeed a member of the “type” argument. This can be done using the “BUILD_BUG_ON_NOT_POWER_OF_2” macro which will produce a compile-time error if the “member” argument is not a power of two.
2. Using the pointer type instead of the structure type
If the structure whose pointer is being passed as an argument is not used in the function, it is more efficient to use the pointer type instead of the structure type. This is because using the structure type will cause the compiler to load the entire structure into memory, while using the pointer type will only load the required pointer into memory. This saves memory and results in faster code execution.
3. Type casts in the macro
It is essential to type cast the pointer passed as an argument to the correct data type. This is because the macro performs pointer arithmetic on the passed pointer. If the pointer type is incorrect, the arithmetic operations will produce incorrect results. In addition, it is important to cast the returned pointer to the correct type before using it in the function.
Now, let us see how to use the “container_of” macro with some examples:
Example 1:
```
struct device {
int id;
char *name;
struct list_head list;
};
struct device *dev;
struct list_head *node;
node = &dev->list; // get pointer to list member
dev = container_of(node, struct device, list); // get pointer to top-level struct
```
In this example, we have a structure “device” which contains an integer “id”, a string “name” and a list_head “list”. We have a pointer to the list_head “list” member and we want to obtain the pointer to the top-level structure “device”. To do this, we pass the pointer to the list_head member and the type of the top-level structure to the “container_of” macro.
Example 2:
```
struct data {
int val;
struct data *next;
};
struct data *ptr;
int num;
ptr = container_of(&num, struct data, val); // get pointer to top-level struct
```
In this example, we want to obtain a pointer to the top-level structure “data” using a pointer to the integer “val”. To do this, we pass the address of the integer “val” as a pointer, the type of the top-level structure and the name of the member (integer) to the “container_of” macro.
In conclusion, the “container_of” macro is a powerful tool that allows developers to access the top-level structure containing a given member pointer. By following the efficient usage guidelines and using examples, you can harness its full potential and optimize your code for speed and memory efficiency.