2015-03-07 6 views
12

ओएस विकास अनुसंधान में अपने प्रयासों को जारी रखते हुए, मैंने अपने सिर में लगभग पूरी तस्वीर बनाई है। एक चीज अभी भी मुझे बढ़ाती है।ऑपरेटिंग सिस्टम कर्नेल और प्रक्रियाओं को मुख्य मेमोरी में

यहाँ मेरी समझ से, बुनियादी बूट प्रक्रिया है:

1) BIOS/बूटलोडर आवश्यक जांच करते हैं, सब कुछ आरंभ कर देगा।

2) कर्नेल रैम में लोड किया गया है।

3) कर्नेल इसकी प्रारंभिकता करता है और शेड्यूलिंग कार्य शुरू करता है।

4) जब कोई कार्य लोड होता है, तो उसे वर्चुअल एड्रेस स्पेस दिया जाता है जिसमें यह रहता है। .text, .data, .bss, ढेर और ढेर सहित। यह कार्य अपने स्वयं के "वर्चुअल" स्टैक को इंगित करते हुए, अपने स्वयं के स्टैक पॉइंटर को "रखता है"।

5) संदर्भ स्विच केवल रजिस्टर फ़ाइल (सभी सीपीयू रजिस्टरों), स्टैक पॉइंटर और प्रोग्राम काउंटर को कुछ कर्नेल डेटा संरचना में धक्का देते हैं और किसी अन्य प्रक्रिया से संबंधित एक और सेट लोड करते हैं।

इस अमूर्तता में, कर्नेल एक "मां" प्रक्रिया है जिसमें अन्य सभी प्रक्रियाओं की मेजबानी की जाती है। मैं निम्न चित्र में मेरे सबसे अच्छे समझ व्यक्त करने की कोशिश की:

enter image description here

प्रश्न है, इस साधारण मॉडल सही है?

दूसरा, निष्पादन योग्य प्रोग्राम को इसके वर्चुअल स्टैक के बारे में पता कैसे लगाया गया है? क्या यह वर्चुअल स्टैक पॉइंटर की गणना करने और प्रासंगिक CPU रजिस्टर में रखने के लिए ओएस नौकरी है? क्या सीपीयू पॉप और पुश कमांड द्वारा किए गए बाकी स्टैक बुककीपिंग हैं?

क्या कर्नेल के पास अपना मुख्य ढेर और ढेर है?

धन्यवाद।

उत्तर

9

प्रश्न है, इस साधारण मॉडल सही है?

आपका मॉडल बेहद सरल है लेकिन अनिवार्य रूप से सही है - ध्यान दें कि आपके मॉडल के अंतिम दो हिस्सों को वास्तव में बूट प्रक्रिया का हिस्सा नहीं माना जाता है, और कर्नेल एक प्रक्रिया नहीं है। इसे एक के रूप में देखने के लिए उपयोगी हो सकता है, लेकिन यह किसी प्रक्रिया की परिभाषा में फिट नहीं होता है और यह एक जैसा व्यवहार नहीं करता है।

दूसरा, निष्पादन योग्य प्रोग्राम को इसके वर्चुअल स्टैक के बारे में पता कैसे लगाया गया है? यह आभासी ढेर सूचक की गणना करने और प्रासंगिक सीपीयू रजिस्टर में रखें को ओएस काम है? सीपीयू पॉप और पुश कमांड द्वारा किए गए बाकी स्टैक बुककीपिंग है?

एक निष्पादन योग्य सी प्रोग्राम को "इसके आभासी ढेर के बारे में पता होना" नहीं होना चाहिए। , [ebp - 4] उदाहरण के लिए - एक सी प्रोग्राम एक निष्पादन में संकलित किया जाता है, तो स्थानीय चर आमतौर पर ढेर सूचक के सापेक्ष में दर्शाया जाता है।

जब लिनक्स निष्पादन के लिए एक नया प्रोग्राम लोड करता है, तो यह CPU के रजिस्टरों को प्रारंभ करने के लिए start_thread मैक्रो (जिसे load_elf_binary से कहा जाता है) का उपयोग करता है।

regs->esp = new_esp; 

जो आभासी पता है कि ओएस धागा के ढेर करने के लिए सौंपा गया है करने के लिए CPU के ढेर सूचक रजिस्टर प्रारंभ हो जाएगा: मैक्रो निम्न पंक्ति में शामिल है।

जैसा कि आपने कहा था, एक बार स्टैक पॉइंटर लोड हो जाने पर, असेंबली कमांड जैसे pop और push इसके मूल्य को बदल देंगे। ऑपरेटिंग सिस्टम यह सुनिश्चित करने के लिए ज़िम्मेदार है कि वर्चुअल स्टैक पतों के अनुरूप भौतिक पृष्ठ हैं - बहुत से स्टैक मेमोरी का उपयोग करने वाले प्रोग्रामों में, भौतिक पृष्ठों की संख्या बढ़ेगी क्योंकि कार्यक्रम इसके निष्पादन को जारी रखता है। प्रत्येक प्रक्रिया है कि आप ulimit -a कमांड का उपयोग करके प्राप्त कर सकते हैं के लिए एक सीमा नहीं है (मेरी मशीन पर अधिकतम ढेर आकार 8MB, या 2KB पृष्ठों है)।

क्या कर्नेल के पास अपना मुख्य ढेर और ढेर है?

यह वह जगह है जहां कर्नेल को एक प्रक्रिया के रूप में कल्पना करना भ्रमित हो सकता है। सबसे पहले, लिनक्स में धागे में उपयोगकर्ता स्टैक और कर्नेल स्टैक होता है। वे अनिवार्य रूप से वही हैं, केवल सुरक्षा और स्थान में भिन्न होते हैं (कर्नेल मोड में निष्पादित करते समय कर्नेल स्टैक का उपयोग किया जाता है, और उपयोगकर्ता मोड में निष्पादित करते समय उपयोगकर्ता स्टैक)।

कर्नेल के पास स्वयं का ढेर नहीं है। कर्नेल कोड हमेशा कुछ थ्रेड के संदर्भ में निष्पादित किया जाता है, और प्रत्येक थ्रेड का अपना निश्चित आकार (आमतौर पर 8 केबी) कर्नेल स्टैक होता है। जब कोई थ्रेड उपयोगकर्ता मोड से कर्नेल मोड में जाता है, तो CPU के स्टैक पॉइंटर को तदनुसार अपडेट किया जाता है। तो जब कर्नेल कोड स्थानीय चर का उपयोग करता है, तो वे उस थ्रेड के कर्नेल स्टैक पर संग्रहीत होते हैं जिसमें वे निष्पादित होते हैं।

सिस्टम स्टार्टअप के दौरान, start_kernel फ़ंक्शन कर्नेल init थ्रेड प्रारंभ करता है, जो तब अन्य कर्नेल थ्रेड बना देगा और उपयोगकर्ता प्रोग्राम प्रारंभ करना शुरू करेगा। तो सिस्टम स्टार्टअप के बाद सीपीयू के स्टैक पॉइंटर को init के कर्नेल स्टैक पर इंगित करने के लिए प्रारंभ किया जाएगा।

जहां तक ​​ढेर जाता है, आप kmalloc का उपयोग कर कर्नेल में गतिशील रूप से स्मृति आवंटित कर सकते हैं, जो स्मृति में एक मुफ्त पृष्ठ खोजने का प्रयास करेगा - इसका आंतरिक कार्यान्वयन get_zeroed_page का उपयोग करता है।

+2

* "कर्नेल के पास स्वयं का ढेर नहीं है।" * गलत नहीं होने पर, मुझे लगता है कि मेरे उत्तर से यह बिंदु ओपी की गलतफहमी को साफ़ करता है: * "जबकि कर्नेल के अपने धागे हो सकते हैं ... कर्नेल को वास्तव में "एक मां प्रक्रिया" के बारे में नहीं सोचा जाना चाहिए जो स्वतंत्र रूप से चलता है ... "* यहां मुख्य टेकवे: ** धागे (कार्यों) में ढेर ** हैं, और उपयोगकर्ता-मोड प्रक्रियाओं और कर्नेल धागे दोनों (उर्फ' लिनक्स में kthread') धागे हैं। इसके अतिरिक्त, उपयोगकर्ता-मोड थ्रेड में वास्तव में एकाधिक स्टैक होंगे: एक उपयोगकर्ता-मोड में, और कर्नेल में दूसरा। –

8

आप एक महत्वपूर्ण बिंदु भूल गए: Virtual memoryहार्डवेयर द्वारा लागू किया गया है, जिसे आम तौर पर एमएमयू (मेमोरी मैनेजमेंट यूनिट) के नाम से जाना जाता है। यह एमएमयू है जो वर्चुअल पतों को भौतिक पते में परिवर्तित करता है।

कर्नेल आम तौर पर एमएमयू में एक रजिस्टर में एक विशिष्ट प्रक्रिया के लिए पृष्ठ तालिका के आधार का पता लोड करता है। यह वर्चुअल मेमोरी स्पेस को एक प्रक्रिया से दूसरी प्रक्रिया में स्विच-स्विच करता है। X86 पर, यह रजिस्टर CR3 है।

वर्चुअल मेमोरी एक दूसरे से प्रक्रियाओं की स्मृति की सुरक्षा करता है। प्रक्रिया ए के लिए रैम बस प्रक्रिया बी में मैप नहीं किया गया है (उदाहरण के लिए shared libraries, जहां स्मृति कोड को बचाने के लिए एक ही कोड मेमोरी को कई प्रक्रियाओं में मैप किया गया है)।

वर्चुअल मेमोरी उपयोगकर्ता-मोड प्रक्रिया से कर्नेल मेमोरी स्पेस को भी सुरक्षित रखती है। कर्नेल पता स्थान को कवर करने वाले पृष्ठों पर विशेषताओं को सेट किया गया है ताकि जब प्रोसेसर उपयोगकर्ता-मोड में चल रहा हो, तो उसे वहां निष्पादित करने की अनुमति नहीं है।

ध्यान दें कि, जबकि कर्नेल में स्वयं के धागे हो सकते हैं, जो पूरी तरह से कर्नेल स्पेस में चलते हैं, कर्नेल को वास्तव में "एक मां प्रक्रिया" के बारे में नहीं सोचना चाहिए जो आपके उपयोगकर्ता-मोड प्रोग्राम से स्वतंत्र रूप से चलता है। कर्नेल मूल रूप से आपके उपयोगकर्ता-मोड प्रोग्राम का "दूसरा आधा" है!जब भी आप एक system call जारी, सीपीयू स्वचालित रूप से कर्नेल मोड में बदलते हैं, और एक पूर्व निर्धारित स्थान, गिरी से निर्धारित पर क्रियान्वित करने शुरू होता है। गिरी सिस्टम कॉल हैंडलर उसके बाद आपकी ओर, अपनी प्रक्रिया की कर्नेल-मोड संदर्भ में पर निष्पादित करता है। आपके अनुरोध को संभालने वाले कर्नेल में बिताए गए समय के लिए जिम्मेदार है, और आपकी प्रक्रिया "चार्ज" की गई है।

3

प्रक्रियाओं और धागे

मॉडल आपके द्वारा प्रदान के साथ संबंधों के संदर्भ में गिरी के बारे में सोच की उपयोगी तरीके बहुत सरल लेकिन सामान्य रूप में सही है। उसी समय कर्नेल के बारे में सोचने का तरीका "मां प्रक्रिया" के बारे में सोचने का तरीका सबसे अच्छा नहीं है, लेकिन यह अभी भी कुछ समझ में है। मैं एक और दो बेहतर मॉडल का प्रस्ताव देना चाहता हूं।

  1. कर्नेल के बारे में विशेष प्रकार की साझा लाइब्रेरी के बारे में सोचने का प्रयास करें। साझा लाइब्रेरी कर्नेल की तरह विभिन्न प्रक्रियाओं के बीच साझा किया जाता है। सिस्टम कॉल एक ऐसे तरीके से किया जाता है जो साझा पुस्तकालय से नियमित कॉल के समान ही है। दोनों मामलों में, कॉल के बाद, आप "विदेशी" कोड निष्पादित करते हैं लेकिन संदर्भ में आपकी मूल प्रक्रिया। और दोनों मामलों में आपका कोड स्टैक के आधार पर गणना करना जारी रखता है। ध्यान दें, कि दोनों मामलों में "विदेशी" कोड को आपके "मूल" कोड के निष्पादन को अवरुद्ध करने का कारण बनता है। कॉल से वापस आने के बाद, कोड के उसी बिंदु पर निष्पादन जारी रहता है और उस स्टैक की उसी स्थिति के साथ जिसमें कॉल किया गया था। लेकिन हम कर्नेल को "विशेष" प्रकार की साझा लाइब्रेरी के रूप में क्यों मानते हैं? क्योंकि:

    ए। कर्नेल एक "लाइब्रेरी" है जिसे सिस्टम में प्रत्येक प्रक्रिया द्वारा साझा किया जाता है।

    बी। कर्नेल एक "लाइब्रेरी" है जो न केवल कोड का अनुभाग साझा करता है, बल्कि डेटा का अनुभाग भी साझा करता है।

    सी। कर्नेल एक विशेष रूप से संरक्षित "लाइब्रेरी" है। आपकी प्रक्रिया सीधे कर्नेल कोड और डेटा तक नहीं पहुंच सकती है। इसके बजाए, इसे विशेष "कॉल गेट्स" के माध्यम से कर्नेल नियंत्रित तरीके से कॉल करने के लिए मजबूर होना पड़ता है।

    डी। सिस्टम कॉल के मामले में आपका एप्लिकेशन वस्तुतः निरंतर ढेर पर निष्पादित होगा। लेकिन हकीकत में यह ढेर दो अलग-अलग हिस्सों से होगा। उपयोगकर्ता मोड में एक भाग का उपयोग किया जाता है और कर्नेल में प्रवेश करते समय दूसरे भाग को आपके उपयोगकर्ता मोड स्टैक के शीर्ष से तार्किक रूप से जोड़ा जाएगा और बाहर निकलने के दौरान हटा दिया जाएगा।

  2. आपके कंप्यूटर में कम्प्यूटेशंस के संगठन के बारे में सोचने का एक और उपयोगी तरीका इसे "आभासी" कंप्यूटरों के नेटवर्क के रूप में माना जाता है, जिसमें वर्चुअल मेमोरी का समर्थन नहीं है। आप वर्चुअल मल्टीप्रोसेसर कंप्यूटर के रूप में प्रक्रिया को देख सकते हैं जो केवल एक प्रोग्राम निष्पादित करता है जिसमें सभी मेमोरी तक पहुंच होती है। इस मॉडल में प्रत्येक "आभासी" प्रोसेसर निष्पादन के धागे द्वारा प्रदर्शित किया जाएगा। जैसे आपके पास एकाधिक प्रोसेसर (या मल्टीकोर प्रोसेसर के साथ) वाला कंप्यूटर हो सकता है, आप अपनी प्रक्रिया में कई बार चल रहे थ्रेड कर सकते हैं। आपके कंप्यूटर में सभी प्रोसेसर ने भौतिक मेमोरी के पूल तक पहुंच साझा की है, आपकी प्रक्रिया के सभी थ्रेड समान वर्चुअल एड्रेस स्पेस तक पहुंच साझा करते हैं। और अलग-अलग कंप्यूटरों की तरह शारीरिक रूप से एक-दूसरे से अलग होते हैं, आपकी प्रक्रियाएं एक दूसरे से अलग होती हैं लेकिन तार्किक रूप से अलग होती हैं। इस मॉडल में कर्नेल को स्टार टोपोलॉजी के साथ नेटवर्क में प्रत्येक कंप्यूटर से सीधा कनेक्शन रखने वाले सर्वर द्वारा दर्शाया जाता है। इसी प्रकार नेटवर्किंग सर्वर के लिए, कर्नेल में दो मुख्य उद्देश्य हैं:

    ए। सर्वर एक ही नेटवर्क में सभी कंप्यूटरों को इकट्ठा करता है। इसी तरह कर्नेल इंटर-प्रोसेस संचार और सिंक्रनाइज़ेशन का माध्यम प्रदान करता है। कर्नेल मध्य में एक आदमी के रूप में काम करता है जो पूरी संचार प्रक्रिया में मध्यस्थता करता है (डेटा स्थानांतरित करता है, मार्ग संदेश और अनुरोध इत्यादि)।

    बी। सर्वर की तरह प्रत्येक जुड़े कंप्यूटर को सेवाओं का कुछ सेट प्रदान करता है, कर्नेल प्रक्रियाओं के लिए सेवाओं का एक सेट प्रदान करता है। उदाहरण के लिए, नेटवर्क फ़ाइल सर्वर की तरह कंप्यूटर साझा स्टोरेज पर स्थित फ़ाइलों को पढ़ने और लिखने की अनुमति देता है, आपका कर्नेल प्रक्रियाओं को एक ही चीज करने की अनुमति देता है लेकिन स्थानीय संग्रहण का उपयोग करता है।

नोट, क्लाइंट-सर्वर संचार प्रतिमान के बाद, नेटवर्क (प्रक्रियाएं) नेटवर्क में एकमात्र सक्रिय अभिनेता हैं। वे सर्वर और एक दूसरे के बीच अनुरोध जारी करते हैं। सर्वर इसकी बारी में सिस्टम का एक प्रतिक्रियाशील हिस्सा है और यह संचार शुरू नहीं करता है। इसके बजाय यह केवल इनकमिंग अनुरोधों का जवाब देता है। यह मॉडल सिस्टम के प्रत्येक भाग और कर्नेल और प्रक्रियाओं के बीच संचार की क्लाइंट-सर्वर प्रकृति के बीच संसाधन साझाकरण/अलगाव संबंधों को प्रतिबिंबित करते हैं।

कैसे ढेर प्रबंधन किया जाता है, और क्या भूमिका है कि इस प्रक्रिया

में गिरी निभाता है जब नई प्रक्रिया शुरू होता है, गिरी, निष्पादन योग्य छवि से संकेत का उपयोग कर, निर्णय लेता है कहाँ और कैसे वर्चुअल ऐड्रेस स्पेस की ज्यादा सुरक्षित होगा प्रक्रिया के प्रारंभिक धागे के उपयोगकर्ता मोड ढेर के लिए। इस निर्णय के बाद, कर्नेल प्रोसेसर रजिस्टरों के सेट के लिए प्रारंभिक मान सेट करता है, जिसे निष्पादन की शुरुआत के बाद प्रक्रिया के मुख्य थ्रेड द्वारा उपयोग किया जाएगा। इस सेटअप में स्टैक पॉइंटर के प्रारंभिक मान की सेटिंग शामिल है। प्रक्रिया निष्पादन की वास्तविक शुरुआत के बाद, प्रक्रिया स्वयं स्टैक पॉइंटर के लिए ज़िम्मेदार हो जाती है। अधिक दिलचस्प तथ्य यह है कि प्रक्रिया इसके द्वारा बनाए गए प्रत्येक नए धागे के स्टैक पॉइंटर्स के प्रारंभ के लिए ज़िम्मेदार है। लेकिन ध्यान दें कि कर्नेल कर्नेल सिस्टम में प्रत्येक थ्रेड के लिए कर्नेल मोड स्टैक के आवंटन और प्रबंधन के लिए ज़िम्मेदार है। ध्यान दें कि कर्नेल स्टैक के लिए भौतिक स्मृति आवंटन के लिए उत्तरदायी है और आमतौर पर पेज दोषों का उपयोग संकेतों के रूप में मांग पर आलसी रूप से इस काम को निष्पादित करता है। चलने वाले थ्रेड के स्टैक पॉइंटर को थ्रेड द्वारा ही प्रबंधित किया जाता है। ज्यादातर मामलों में स्टैक पॉइंटर प्रबंधन कंपाइलर द्वारा किया जाता है, जब यह निष्पादन योग्य छवि बनाता है। कंपाइलर आमतौर पर स्टैक पॉइंटर मान ट्रैक करता है और स्टैक से संबंधित सभी निर्देशों को जोड़कर और ट्रैकिंग करके इसकी स्थिरता बनाए रखता है। ऐसे निर्देश केवल "पुश" और "पॉप" द्वारा सीमित नहीं हैं। कई सीपीयू निर्देश हैं जो स्टैक को प्रभावित करते हैं, उदाहरण के लिए "कॉल" और "रेट", "सब ईएसपी" और "ईएसपी जोड़ें", आदि ताकि आप देख सकें, स्टैक पॉइंटर प्रबंधन की वास्तविक नीति ज्यादातर स्थिर और ज्ञात है प्रक्रिया निष्पादन से पहले। कभी-कभी प्रोग्राम में तर्क का एक विशेष हिस्सा होता है जो विशेष स्टैक प्रबंधन करता है। उदाहरण के लिए सी में कोरआउट या लंबी कूद के कार्यान्वयन के लिए, वास्तव में, यदि आप चाहें तो अपने कार्यक्रम में स्टैक पॉइंटर के साथ जो कुछ भी आप चाहते हैं उसे करने की अनुमति है।

कर्नेल ढेर आर्किटेक्चर

मैं इस मुद्दे के लिए तीन तरीके के बारे में जागरूक कर रहा हूँ:

  1. अलग गिरी प्रणाली में धागा प्रति ढेर। विंडोज, लिनक्स, यूनिक्स, मैकोज़ सहित मोनोलिथिक कर्नेल के आधार पर यह सबसे प्रसिद्ध ओएस द्वारा अपनाया गया एक दृष्टिकोण है। हालांकि यह दृष्टिकोण मेमोरी और खराब कैश उपयोग के मामले में महत्वपूर्ण ओवरहेड की ओर जाता है, लेकिन यह कर्नेल की छूट में सुधार करता है, जो मोनोलिथिक कर्नेल के लिए महत्वपूर्ण है, विशेष रूप से बहु-प्रोसेसर वातावरण में लंबे समय से चलने वाली सिस्टम कॉल के साथ। असल में, लंबे समय पहले लिनक्स में केवल एक साझा कर्नेल स्टैक था और पूरे कर्नेल को बिग कर्नेल लॉक द्वारा कवर किया गया था जो धागे की संख्या को सीमित करता है, जो एक ही थ्रेड द्वारा समेकित रूप से सिस्टम कॉल कर सकता है। लेकिन लिनक्स कर्नेल डेवलपर्स ने तुरंत पहचान लिया है कि एक प्रक्रिया के निष्पादन को अवरुद्ध करना जो उदाहरण के लिए पीआईडी ​​जानना चाहता है, क्योंकि एक और प्रक्रिया पहले ही बहुत धीमी नेटवर्क के माध्यम से एक बड़े पैकेट को भेजना शुरू कर चुकी है, पूरी तरह से अक्षम है।

  2. एक साझा कर्नेल स्टैक। ट्रेडऑफ microkernels के लिए बहुत अलग है। लघु प्रणाली कॉल के साथ छोटे कर्नेल microkernel डिजाइनरों को एकल कर्नेल स्टैक के साथ डिजाइन करने के लिए चिपकने की अनुमति देता है। सबूत की उपस्थिति में कि सभी सिस्टम कॉल बेहद कम हैं, वे बेहतर कैश उपयोग और छोटी मेमोरी ओवरहेड से लाभ उठा सकते हैं, लेकिन फिर भी अच्छे स्तर पर सिस्टम प्रतिक्रिया को बनाए रखें।

  3. सिस्टम में प्रत्येक प्रोसेसर के लिए कर्नेल स्टैक। माइक्रोकॉर्नल ओएस में भी एक साझा कर्नेल स्टैक मल्टीप्रोसेसर पर्यावरण में पूरे ऑपरेटिंग सिस्टम की स्केलेबिलिटी को गंभीरता से प्रभावित करता है। इसके कारण, डिजाइनर अक्सर दृष्टिकोण का पालन करते हैं जो ऊपर वर्णित दो दृष्टिकोणों के बीच समझौता की तरह दिखता है, और सिस्टम में प्रत्येक प्रोसेसर (प्रोसेसर कोर) के प्रति एक कर्नेल स्टैक रखें। उस स्थिति में उन्हें अच्छे कैश उपयोग और छोटे मेमोरी ओवरहेड से लाभ होता है, जो स्टैक प्रति थ्रेड दृष्टिकोण से थोड़ा बेहतर होता है और एकल साझा स्टैक दृष्टिकोण की तुलना में थोड़ा खराब होता है। और साथ ही वे सिस्टम की अच्छी मापनीयता और प्रतिक्रिया से लाभ उठाते हैं।

धन्यवाद।

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