लिनक्स कर्नेल में कंटेनर_ऑफ मैक्रो को समझना


84

जब मैं लिनक्स कर्नेल ब्राउज़ कर रहा था, तो मुझे एक container_ofमैक्रो मिला जिसे इस प्रकार परिभाषित किया गया है:

मैं समझता हूं कि कंटेनर_ क्या करता है, लेकिन मैं जो नहीं समझता वह अंतिम वाक्य है, जो है

यदि हम मैक्रो का उपयोग इस प्रकार करें:

अंतिम वाक्य का संगत हिस्सा होगा:

जो कुछ भी नहीं करने जैसा लगता है। क्या कोई कृपया यहां शून्य भर सकता है?


1
इस उत्तर में लाल-काले पेड़ का उपयोग करके एक वास्तविक और सहज उदाहरण है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
आप में से जो लोग अधिक विस्तृत विवरण की जरूरत के लिए: राडेक Pazdera समझाया container_of मैक्रो ( include/linux/kernel.hपर) वास्तव में स्पष्ट रूप से अपने ब्लॉगBTW : list_entry मैक्रो ( include/linux/list.h) को बहुत समान रूप से परिभाषित किया जाता था, लेकिन अब इसे परिभाषित किया गया है container_of
patryk.beza

1
ग्रेग क्रोहा-हार्टमैन का यह ब्लॉगपोस्ट उपयोगी हो सकता है: kroah.com/log/linux/container_of.html
EFraim

1
सिद्धांत रूप में, यह एक अच्छा जवाब है, सिवाय इसके कि यह वास्तव में प्रश्न के काफी टुकड़े का जवाब नहीं देता है? उदाहरण के लिए, कोड की अंतिम पंक्ति क्या प्राप्त करती है और कैसे?
माइकल बीयर

जब मैं इस उदाहरण का पालन करता हूं, तो जीसीसी का उपयोग करके मुझे प्राप्त होता है error: initialization from incompatible pointer type। क्या इस constधागे के अनुसार मैक्रो की परिभाषा के कारण ऐसा है? stackoverflow.com/a/39963179/1256234
एंडी जे

18

अंतिम वाक्य डाला:

किसी दिए गए एक सूचक type। सूचक की गणना किसी दिए गए सूचक से ऑफसेट के रूप में की जाती है dev:

जब आप cointainer_ofमैक्रो का उपयोग करते हैं , तो आप उस संरचना को पुनः प्राप्त करना चाहते हैं जिसमें किसी दिए गए फ़ील्ड का पॉइंटर होता है। उदाहरण के लिए:

आपके पास एक संकेतक है जो एक संरचना के बीच में इंगित करता है (और आप जानते हैं कि दायर two[ संरचना में क्षेत्र का नाम ] के लिए एक सूचक है ), लेकिन आप पूरी संरचना ( numbers) को पुनः प्राप्त करना चाहते हैं । तो, आप twoसंरचना में दर्ज किए गए ऑफसेट की गणना करते हैं :

और दिए गए पॉइंटर से इस ऑफसेट को घटाएं। परिणाम संरचना की शुरुआत के लिए सूचक है। अंत में, आप इस पॉइंटर को एक वैध चर के लिए संरचना प्रकार में डालते हैं।


10

यह gcc एक्सटेंशन, स्टेटमेंट एक्सप्रेशन का उपयोग है । यदि आप मैक्रो को किसी मान के रूप में लौटते हुए देखते हैं, तो अंतिम पंक्ति होगी:

यौगिक कथनों की व्याख्या के लिए जुड़ा हुआ पृष्ठ देखें। यहाँ एक उदाहरण है :

आउटपुट है

बी 25


7

लिनक्स कर्नेल में conatainer_of () मैक्रो -

जब कोड में कई डेटा संरचनाओं का प्रबंधन करने की बात आती है, तो आपको लगभग हमेशा एक संरचना को दूसरे में एम्बेड करने और किसी भी क्षण उन्हें पुनर्प्राप्त करने की आवश्यकता होगी, बिना मेमोरी ऑफ़सेट्स या सीमाओं के बारे में प्रश्न पूछे जाने पर। मान लें कि आपके पास एक संरचनात्मक व्यक्ति है, जैसा कि यहां परिभाषित किया गया है:

केवल उम्र या वेतन पर एक पॉइंटर होने से, आप उस पॉइंटर को पूरी तरह से लपेटकर (युक्त) प्राप्त कर सकते हैं। जैसा कि नाम कहता है, कंटेनर_ऑफ मैक्रो का उपयोग किसी संरचना के दिए गए क्षेत्र के कंटेनर को खोजने के लिए किया जाता है। मैक्रो में शामिल / linux / kernel.h परिभाषित किया गया है और निम्नलिखित की तरह दिखता है:

संकेत से डरो मत; बस उन्हें इस प्रकार देखें:

यहां पूर्ववर्ती कोड टुकड़े के तत्व दिए गए हैं:

  • पॉइंटर: यह संरचना में क्षेत्र का सूचक है
  • कंटेनर_टाइप: यह पॉइंटर को लपेटने (युक्त) का प्रकार है
  • कंटेनर_फील्ड: यह उस क्षेत्र का नाम है, जो संरचना के अंदर इंगित करता है

चलो निम्नलिखित कंटेनर पर विचार करें:

अब, आइए, इसके एक उदाहरण पर विचार करें, साथ ही उम्र के सदस्य को एक संकेत दें:

नाम सदस्य (age_ptr) के लिए एक पॉइंटर के साथ, आप कंटेनर (मैक्रो) का उपयोग कर सकते हैं ताकि पूरी संरचना (कंटेनर) को एक पॉइंटर मिल सके जो इस सदस्य को निम्नलिखित का उपयोग करके लपेटता है:

कंटेनर_ऑफ सही पॉइंटर स्थान प्राप्त करने के लिए संरचना की शुरुआत में उम्र की भरपाई करता है। यदि आप सूचक age_ptr से फ़ील्ड आयु की ऑफ़सेट घटाते हैं, तो आपको सही स्थान मिलेगा। यह मैक्रो की अंतिम पंक्ति है:

इसे एक वास्तविक उदाहरण पर लागू करना, निम्नलिखित देता है:

कंटेनर_ऑफ मैक्रो का उपयोग मुख्य रूप से कर्नेल में जेनेरिक कंटेनरों में किया जाता है।

यह सब के बारे में कंटेनर_ऑफ मैक्रो कर्नेल में है।


3

एक छोटा सा वास्तविक संदर्भ स्पष्ट करता है, नीचे लाल-काले पेड़ का उपयोग उदाहरण के रूप में किया जाता है, जो कि मेरे समझने का तरीका हैcontainer_of

जैसा कि Documentation/rbtree.txtराज्यों में, लिनक्स कर्नेल कोड में, यह rb_node डेटा प्रविष्टि नहीं है, बल्कि है

एक rbtree ट्री में डेटा नोड एक स्ट्रक्चर है जिसमें एक स्ट्रक्चर 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
  • membertypeउदाहरण के सदस्य का नाम है , यहाँ vm_rb, जो प्रकार का है rb_node,
  • ptrmemberएक typeउदाहरण की ओर इशारा करते हुए सूचक है , यहाँ rb_node *nd

क्या container_ofइस उदाहरण में, करते हैं,

  • obj.member(यहां obj.vm_rb) का पता दिया गया है , का पता वापस करें obj
  • के बाद से एक struct सन्निहित स्मृति का एक ब्लॉक है, का पता 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मतलब kth लाइन इन file



0

कंटेनर _of मैक्रो का सबसे सरल कार्यान्वयन नीचे है, यह प्रकार और कार्यों की सभी जटिल जाँच को कम करता है

ptr सदस्य का पता देगा और ऑफसेट अंतर को घटाएगा और आपको प्रारंभ पता मिल जाएगा।

उदाहरण उपयोग

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.