programing

Linux 커널의 container_of 매크로 이해

javaba 2022. 7. 17. 11:36
반응형

Linux 커널의 container_of 매크로 이해

때 했습니다.container_of매크로의 정의는 다음과 같습니다.

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

container_of가 무엇을 하는지 이해는 하지만 내가 이해하지 못하는 것은 마지막 문장이다.

(type *)( (char *)__mptr - offsetof(type,member) );})

매크로를 다음과 같이 사용하는 경우:

container_of(dev, struct wifi_device, dev);

마지막 문장에 해당하는 부분은 다음과 같습니다.

(struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev);

아무것도 안 하는 것처럼 보이는군여기 빈자리를 채워줄 사람 있나요?

예 " " "container_of(dev, struct wifi_device, dev);두 개의 네임스페이스를 섞어서 조금 오해의 소지가 있습니다.

첫 번째 " "는"입니다.dev에서는 두 번째 .dev는 구조체 멤버의 이름을 나타냅니다.

아마 이 혼란이 그 모든 두통을 유발하고 있을 것이다. 실,, 그 inmember인용문의 매개 변수는 컨테이너 구조에서 해당 멤버에게 지정된 이름을 나타냅니다.

이 컨테이너를 예로 들어 보겠습니다.

struct container {
  int some_other_data;
  int this_data;
}

포인터 ★★★★★★★★★★★★★★★★★★★★」int *my_ptrthis_data 매크로를 수 struct container *my_container★★★★★★★★★★★★★★★★★★:

struct container *my_container;
my_container = container_of(my_ptr, struct container, this_data);

of of of of of of of of of of of of of of의 을 취해서.this_data올바른 포인터 위치를 얻는 데 필수적입니다.

.this_datamy_ptr을 사용하다

이것이 바로 매크로의 마지막 행이 하는 일입니다.

마지막 문장은 다음과 같습니다.

(type *)(...)

type 포인터로부터의 dev:

( (char *)__mptr - offsetof(type,member) )

「 」를하는 cointainer_of매크로에서는 특정 필드의 포인터를 포함하는 구조를 가져옵니다.예를 들어:예를들어 다음과 같습니다.

struct numbers {
    int one;
    int two;
    int three;
} n;

int *ptr = &n.two;
struct numbers *n_ptr;
n_ptr = container_of(ptr, struct numbers, two);

당신은 어떤 구조(그리고, 파일에 저장된구조물 중앙을가리키는 포인터가 있습니다는 포인터(또한 해당 포인터가 파일로의 포인터임을 알고 있습니다 알아)의 중간에는 지적 포인트를 가지고 있다.two[구조체의 필드 이름])를 사용하지만 전체 구조체를 검색해야 합니다.numbers). 그래서, 파일에 저장된)그래서 필드의 오프셋을 계산합니다의 오프셋을 계산한다.two구조체에:구조 내:

offsetof(type,member)

지정된 포인터에서 이 오프셋을 뺍니다.결과는 구조체의 시작에 대한 포인터입니다.마지막으로 유효한 변수를 가지려면 이 포인터를 구조물 유형으로 캐스팅합니다.

Linux 커널의 conatainer_of() 매크로 -

코드의 여러 데이터 구조를 관리하는 경우, 메모리 오프셋이나 경계에 대한 질문을 받지 않고 어떤 구조를 다른 구조에 삽입하여 언제든지 검색할 필요가 있습니다.예를 들어 다음과 같이 구조적인 사람이 있다고 가정합니다.

 struct person { 
     int age; 
     int salary;
     char *name; 
 } p;

나이 또는 급여에 대한 포인터만 있으면 해당 포인터를 래핑(포함)하는 전체 구조를 검색할 수 있습니다.이름에서 알 수 있듯이 container_of macro는 구조체의 지정된 필드의 컨테이너를 찾기 위해 사용됩니다.이 매크로는 include/linux/kernel.h에 정의되어 있으며 다음과 같습니다.

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

포인트는 두려워하지 말고 다음과 같이 확인하시기 바랍니다.

container_of(pointer, container_type, container_field); 

위의 코드 프래그먼트의 요소를 다음에 나타냅니다.

  • 포인터:이것은 구조체의 필드에 대한 포인터입니다.
  • container_type:포인터를 래핑(포함)하는 구조 유형입니다.
  • container_field:포인터가 구조물 내부를 가리키는 필드 이름입니다.

다음 컨테이너에 대해 생각해 보겠습니다.

struct person { 
    int age; 
    int salary; 
    char *name; 
}; 

이제 해당 인스턴스 중 하나와 연령 구성원에 대한 포인터를 살펴보겠습니다.

struct person somebody; 
[...] 
int *age_ptr = &somebody.age; 

name member(age_ptr)에 대한 포인터와 함께 container_of macro를 사용하여 다음을 사용하여 이 멤버를 랩하는 전체 구조(컨테이너)에 대한 포인터를 얻을 수 있습니다.

struct person *the_person; 
the_person = container_of(age_ptr, struct person, age); 

container_of는 올바른 포인터 위치를 얻기 위해 구조체 시작 부분의 경과시간 오프셋을 고려합니다.포인터 age_ptr에서 필드 에이징 오프셋을 빼면 올바른 위치를 얻을 수 있습니다.매크로의 마지막 행은 다음과 같습니다.

(type *)( (char *)__mptr - offsetof(type,member) ); 

이것을 실제의 예에 적용하면, 다음과 같이 됩니다.

struct family { 
    struct person *father; 
    struct person *mother; 
    int number_of_sons; 
    int family_id; 
} f; 

/*   
 * Fill and initialise f somewhere   */      [...]

 /* 
  * pointer to a field of the structure 
  * (could be any (non-pointer) member in the structure) 
  */ 
   int *fam_id_ptr = &f.family_id; 
   struct family *fam_ptr; 

   /* now let us retrieve back its family */ 
   fam_ptr = container_of(fam_id_ptr, struct family, family_id); 

container_of macro는 주로 커널의 일반 컨테이너에서 사용됩니다.

이것이 커널에 있는 매크로의 container_of macro에 대한 것입니다.

이것은 gcc 확장자, 즉 문장의 식 활용입니다.매크로가 값을 반환하는 것으로 표시되는 경우 마지막 행은 다음과 같습니다.

return (struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev);

복합문에 대한 설명은 링크된 페이지를 참조하십시오.다음은 예를 제시하겠습니다.

int main(int argc, char**argv)
{
    int b;
    b = 5;
    b = ({int a; 
            a = b*b; 
            a;});
    printf("b %d\n", b); 
}

출력은

b 25

Linux 커널의 container_of macro를 이해하기 위한 매우 유용한 링크입니다.https://linux-concepts.blogspot.com/2018/01/understanding-containerof-macro-in.html

약간 실제적인 맥락에서는 더 명확하다고 합니다.아래는 빨간색-검은색 트리를 예로 사용합니다.이것이 제가 이해한 방법입니다.container_of.

~하듯이로Documentation/rbtree.txt미국,linux 커널 코드에서 그것 rb_node 커널 코드에서는 rb_node에 데이터 엔트리가 포함되어 있지 않습니다 데이터 입력, 리눅스를 봉쇄하지는 못합니다.

rbtree 트리 내의 데이터 노드는 구조 rb_node 부재를 포함하는 구조이다.

struct vm_area_struct(에서 파일include/linux/mm_types.h:284cm는 그러한 구조,

같은 파일에는 매크로다.rb_entry으로 정의된다

#define rb_entry(ptr, type, member) container_of(ptr, type, member)

확실히.rb_entry동일하다container_of.

mm/mmap.c:299내부 함수 정의browse_rb, 의 용도가 있습니다.rb_entry:

static int browse_rb(struct mm_struct *mm)
{
    /* two line code not matter */
    struct rb_node *nd, *pn = NULL; /*nd, first arg, i.e. ptr. */
    unsigned long prev = 0, pend = 0;

    for (nd = rb_first(root); nd; nd = rb_next(nd)) {
        struct vm_area_struct *vma;
        vma = rb_entry(nd, struct vm_area_struct, vm_rb);   
        /* -- usage of rb_entry (equivalent to container_of) */
        /* more code not matter here */

이제 알 수 있다container_of(ptr, type, member),

  • type컨테이너 구조입니다.여기는struct vm_area_struct
  • member멤버 이름type인스턴스, 여기서vm_rb의 타입입니다.rb_node,
  • ptr포인터가 가리키고 있다.membertype인스턴스, 여기서rb_node *nd.

container_ofdo는 이 예시와 같이

  • 주어진 주소obj.member(여기서)obj.vm_rb의 주소를 반환한다.obj.
  • 구조는 연속된 메모리의 블록이기 때문에 마이너스 주소는 컨테이너의 주소가 됩니다.

include/linux/kernel.h:858-- 의 정의container_of

include/linux/rbtree.h:51-- 의 정의rb_entry

mm/mmap.c:299-- 사용방법rb_entry

include/linux/mm_types.h:284--struct vm_area_struct

Documentation/rbtree.txt:-- 적-흑 트리의 문서화

include/linux/rbtree.h:36-- 의 정의struct rb_node

추신.

위의 파일은 현재 개발 버전입니다.4.13.0-rc7.

file:k평균 k번째 줄file.

매크로의 가장 간단한 컨테이너 구현은 다음과 같습니다. 모든 복잡한 유형 및 작동 검사를 줄여줍니다.

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member))) 

ptr은 멤버의 주소를 제공하고 오프셋 차이를 빼면 시작 주소를 얻을 수 있습니다.

사용 예

struct sample {
    int mem1;
    char mem2;
    int mem3;
};
int main(void)
{

struct sample sample1;

printf("Address of Structure sample1 (Normal Method) = %p\n", &sample1);
printf("Address of Structure sample1 (container_of Method) = %p\n", 
                        container_of(&sample1.mem3, struct sample, mem3));

return 0;
}

언급URL : https://stackoverflow.com/questions/15832301/understanding-container-of-macro-in-the-linux-kernel

반응형