2013-06-07 8 views
13

मल्टीप्रोसेसर पर, प्रत्येक कोर के अपने चर हो सकते हैं। मैंने सोचा कि वे अलग-अलग पतों में अलग-अलग चर हैं, हालांकि वे एक ही प्रक्रिया में हैं और एक ही नाम हैं।लिनक्स कर्नेल में percpu पॉइंटर्स कैसे कार्यान्वित किए जाते हैं?

लेकिन मुझे आश्चर्य है, कर्नेल इसे कैसे कार्यान्वित करता है? क्या यह सभी percpu पॉइंटर्स जमा करने के लिए स्मृति के एक टुकड़े को बांटता है, और हर बार जब यह सूचक को शिफ्ट या कुछ के साथ कुछ पते पर रीडायरेक्ट करता है?

उत्तर

20

सामान्य वैश्विक चर प्रति CPU नहीं हैं। स्वचालित वैरिएबल स्टैक पर हैं, और विभिन्न सीपीयू अलग-अलग ढेर का उपयोग करते हैं, इसलिए स्वाभाविक रूप से उन्हें अलग-अलग चर मिलते हैं।

मुझे लगता है कि आप लिनक्स के प्रति-CPU चरणीय आधारभूत संरचना का जिक्र कर रहे हैं।
जादू से अधिकांश यहाँ है (asm-generic/percpu.h):

extern unsigned long __per_cpu_offset[NR_CPUS]; 

#define per_cpu_offset(x) (__per_cpu_offset[x]) 

/* Separate out the type, so (int[3], foo) works. */ 
#define DEFINE_PER_CPU(type, name) \ 
    __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name 

/* var is in discarded region: offset to particular copy we want */ 
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) 
#define __get_cpu_var(var) per_cpu(var, smp_processor_id()) 

मैक्रो RELOC_HIDE(ptr, offset) बस ptr अग्रिम द्वारा बाइट में ऑफसेट दिया (सूचक प्रकार की परवाह किए बिना)।

यह क्या करता है?

  1. जब DEFINE_PER_CPU(int, x) को परिभाषित करने, एक पूर्णांक __per_cpu_x विशेष .data.percpu खंड में बनाया जाता है।
  2. जब कर्नेल लोड होता है, तो यह खंड कई बार लोड होता है - एक बार प्रति CPU (जादू का यह हिस्सा उपरोक्त कोड में नहीं है)।
  3. __per_cpu_offset सरणी प्रतियों के बीच की दूरी से भरा हुआ है। मानते हैं कि प्रति सीपीयू डेटा के 1000 बाइट्स का उपयोग किया जाता है, __per_cpu_offset[n] में 1000*n होगा।
  4. प्रतीक per_cpu__x को लोड के दौरान, CPU 0 के per_cpu__x पर स्थानांतरित किया जाएगा।
  5. __get_cpu_var(x), जब CPU 3 पर चल रहा है, तो *RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3]) पर अनुवाद करेगा। यह सीपीयू 0 के x के साथ शुरू होता है, सीपीयू 0 के डेटा और सीपीयू 3 के बीच ऑफ़सेट जोड़ता है, और अंततः परिणामस्वरूप सूचक को हटा देता है।
+0

आपके उत्तरदाता के लिए धन्यवाद, लेकिन मेरे पास अभी भी कुछ प्रश्न हैं, एसएमपी के लिए नया, इसलिए, आपके विचार पर कोई अपराध नहीं है। सबसे पहले, मैंने सोचा कि एक ही प्रक्रिया में एक ही ढेर होना चाहिए, यहां पॉज़िक्स में थ्रेड परिभाषा है "... और स्वचालित चर, एक ही प्रक्रिया में सभी धागे के लिए सुलभ हैं।" स्वचालित चर धागे द्वारा साझा किया जाता है। विभिन्न प्रोसेसर में अलग-अलग स्टैक सेगमेंट रजिस्टर हो सकते हैं, लेकिन सामग्री एक जैसी होनी चाहिए। दूसरा, क्या हम कह सकते हैं कि अगर हम चाहते हैं तो हम अन्य सीपीयू के चर का उपयोग भी कर सकते हैं, बस percpu द्वारा प्राप्त ऑफसेट को वापस रोल करें? – dspjm

+0

जब दो थ्रेड फ़ंक्शन 'foo' कहते हैं, जिसमें एक स्वचालित चर 'x' है, तो दो स्टैक्स और 'x' के दो उदाहरण होते हैं। प्रत्येक के पास एक अलग पता होता है, और यदि दोनों पते हैं तो दोनों धागे दोनों तक पहुंच सकते हैं। लिनक्स के प्रति-सीपीयू चर के साथ, 'per_cpu (var, cpu)' आपको किसी भी cpu के चरों तक पहुंचने देता है। – ugoren

+0

.data.percpu सेक्शन कैसे निर्धारित करता है कि क्या percpu चर ढेर या ढेर पर घोषित किया गया है? – user31986

संबंधित मुद्दे