Linux 커널의 container_of 매크로 이해


84

Linux 커널을 탐색 할 때 container_of다음과 같이 정의 된 매크로를 찾았습니다 .

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

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

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

아무것도하지 않는 것 같습니다. 아무도 여기서 공백을 채울 수 있습니까?


1
이 답변 에는 red-black tree 사용 하는 실제적이고 직관적 인 예가rb_node 있습니다.
qeatzy

답변:


87

container_of(dev, struct wifi_device, dev);두 개의 네임 스페이스를 혼합 할 때 사용 예제 가 약간 오해의 소지가있을 수 있습니다.

dev예제 에서 첫 번째 는 포인터의 이름을 참조하고 두 번째 dev는 구조 멤버의 이름을 참조합니다.

아마도 이러한 혼합이 그 모든 두통을 유발할 것입니다. 실제로 member인용문 의 매개 변수는 컨테이너 구조에서 해당 멤버에 지정된 이름을 나타냅니다.

이 컨테이너를 예로 들면 :

그리고 포인터를 int *my_ptr받는 this_data회원은 당신에 대한 포인터를 얻기 위해 매크로를 사용하십시오 struct container *my_container사용하여 :

this_data구조체의 시작 부분까지 의 오프셋 을 고려하는 것은 올바른 포인터 위치를 얻는 데 필수적입니다.

실제로 this_data포인터 에서 멤버의 오프셋을 빼서 my_ptr올바른 위치를 가져 오면됩니다.

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


5
좀 더 자세한 설명이 필요한 분들을 위해 : Radek Pazdera 자신의 블로그 에서 container_of macro ( include/linux/kernel.h)를 매우 명확하게 설명 했습니다 . BTW : list_entry 매크로 ( include/linux/list.h)는 예전에는 매우 비슷하게 정의 되었지만 지금은 container_of.
patryk.beza

1
또한 Greg Kroah-Hartman의이 블로그 게시물이 유용 할 수 있습니다. kroah.com/log/linux/container_of.html
EFraim

1
원칙적으로 그것은 좋은 대답입니다.하지만 질문의 상당 부분에 실제로 대답하지 않는다는 점을 제외 하고는 요? 예를 들어, 마지막 코드 줄은 무엇을 어떻게 달성합니까?
Michael Beer

이 예제를 따르면 GCC를 사용하면 error: initialization from incompatible pointer type. 이것은로 인해 const이 스레드에 따라 매크로 정의? stackoverflow.com/a/39963179/1256234
Andy J

18

마지막 문장 :

주어진 type. 포인터는 주어진 포인터의 오프셋으로 계산됩니다 dev.

cointainer_of매크로 를 사용할 때 주어진 필드의 포인터를 포함하는 구조를 검색하려고합니다. 예를 들면 :

구조의 중간을 가리키는 포인터가 있지만 (그리고 그것이 two[ 구조의 필드 이름 ] 파일에 대한 포인터라는 것을 알고 있습니다 ) 전체 구조를 검색하려고합니다 ( numbers). 따라서 two구조 에있는 파일의 오프셋을 계산합니다 .

주어진 포인터에서이 오프셋을 뺍니다. 결과는 구조의 시작에 대한 포인터입니다. 마지막으로 유효한 변수를 갖도록이 포인터를 구조 유형으로 캐스트합니다.


10

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

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

출력은

b 25


7

Linux 커널의 conatainer_of () 매크로-

코드에서 여러 데이터 구조를 관리 할 때 거의 항상 한 구조를 다른 구조에 포함하고 메모리 오프셋이나 경계에 대한 질문없이 언제든지 검색해야합니다. 여기에 정의 된대로 구조체 사람이 있다고 가정 해 보겠습니다.

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

포인터를 두려워하지 마십시오. 다음과 같이 참조하십시오.

다음은 이전 코드 조각의 요소입니다.

  • 포인터 : 구조의 필드에 대한 포인터입니다.
  • container_type : 포인터를 감싸는 (포함) 구조의 유형입니다.
  • container_field : 포인터가 구조 내부를 가리키는 필드의 이름입니다.

다음 컨테이너를 고려해 보겠습니다.

이제 나이 멤버에 대한 포인터와 함께 인스턴스 중 하나를 고려해 보겠습니다.

이름 멤버 (age_ptr)에 대한 포인터와 함께 다음을 사용하여이 멤버를 래핑하는 전체 구조 (컨테이너)에 대한 포인터를 가져 오기 위해 container_of 매크로를 사용할 수 있습니다.

container_of는 올바른 포인터 위치를 얻기 위해 구조체 시작 부분의 age 오프셋을 고려합니다. 포인터 age_ptr에서 필드 age의 오프셋을 빼면 올바른 위치를 얻을 수 있습니다. 이것은 매크로의 마지막 줄이하는 일입니다.

이것을 실제 예제에 적용하면 다음이 제공됩니다.

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

이것이 커널의 container_of 매크로에 관한 것입니다.


3

약간의 실제 컨텍스트는 더 명확하다고 말합니다. 아래에서 빨간색-검정색 트리를 예로 사용 하십시오 container_of.

Documentation/rbtree.txt리눅스 커널 코드의 상태, 그것은 rb_node 아니라, 데이터 항목이 포함 아니에요

rbtree 트리의 데이터 노드는 struct rb_node 멤버를 포함하는 구조입니다.

struct vm_area_struct(파일에서 include/linux/mm_types.h:284)는 그러한 구조입니다.

같은 파일에 rb_entry다음과 같이 정의 된 매크로 가 있습니다.

명확 rb_entry와 동일합니다 container_of.

에서 mm/mmap.c:299내부 함수 정의 browse_rb의 사용이있다 rb_entry:

이제에서 명확합니다 container_of(ptr, type, member).

  • type 컨테이너 구조체입니다. struct vm_area_struct
  • member회원의 이름 type예, 여기 vm_rb유형이다 rb_node,
  • ptr여기 member에서 type인스턴스를 가리키는 포인터 rb_node *nd입니다.

무엇을 container_of할 것은,이 예에서와 같이,이다

  • obj.member(여기 obj.vm_rb)의 주소가 주어지면의 주소를 반환합니다 obj.
  • 구조체는 연속 메모리 블록 이므로 obj.vm_rb마이너스 주소 offset between the struct and member는 컨테이너의 주소가됩니다.

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.



0

Container _of 매크로의 가장 간단한 구현은 다음과 같습니다.

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

사용 예

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.