Linux Exec सिस्टम कॉल

Linux Exec System Call

निष्पादन सिस्टम कॉल का उपयोग एक सक्रिय प्रक्रिया में रहने वाली फ़ाइल को निष्पादित करने के लिए किया जाता है। जब निष्पादन कहा जाता है तो पिछली निष्पादन योग्य फ़ाइल को बदल दिया जाता है और नई फ़ाइल निष्पादित की जाती है।

अधिक सटीक रूप से, हम कह सकते हैं कि निष्पादन सिस्टम कॉल का उपयोग पुरानी फ़ाइल या प्रोग्राम को प्रक्रिया से एक नई फ़ाइल या प्रोग्राम से बदल देगा। प्रक्रिया की पूरी सामग्री को एक नए कार्यक्रम के साथ बदल दिया गया है।







उपयोगकर्ता डेटा खंड जो निष्पादन () सिस्टम कॉल को निष्पादित करता है, को डेटा फ़ाइल से बदल दिया जाता है जिसका नाम निष्पादन () को कॉल करते समय तर्क में प्रदान किया जाता है।



नया प्रोग्राम उसी प्रक्रिया स्थान में लोड किया गया है। वर्तमान प्रक्रिया सिर्फ एक नई प्रक्रिया में बदल गई है और इसलिए प्रक्रिया आईडी पीआईडी ​​​​नहीं बदला गया है, ऐसा इसलिए है क्योंकि हम एक नई प्रक्रिया नहीं बना रहे हैं हम सिर्फ एक प्रक्रिया को निष्पादन में दूसरी प्रक्रिया के साथ बदल रहे हैं।



यदि वर्तमान में चल रही प्रक्रिया में एक से अधिक थ्रेड हैं तो सभी थ्रेड समाप्त हो जाएंगे और नई प्रक्रिया छवि लोड की जाएगी और फिर निष्पादित की जाएगी। वर्तमान प्रक्रिया के धागे को समाप्त करने वाले कोई विनाशक कार्य नहीं हैं।





प्रक्रिया का PID नहीं बदला जाता है, लेकिन प्रक्रिया के डेटा, कोड, स्टैक, हीप आदि को बदल दिया जाता है और उन्हें नई लोड की गई प्रक्रिया से बदल दिया जाता है। नई प्रक्रिया को प्रवेश बिंदु से निष्पादित किया जाता है।

Exec सिस्टम कॉल फ़ंक्शंस का एक संग्रह है और C प्रोग्रामिंग भाषा में, इन फ़ंक्शंस के लिए मानक नाम इस प्रकार हैं:



  1. बहिष्कृत
  2. execle
  3. निष्पादन
  4. कार्यकारी
  5. क्रियान्वित करना
  6. कार्यकारी


यहां यह ध्यान दिया जाना चाहिए कि इन कार्यों का एक ही आधार है कार्यकारी उसके बाद एक या अधिक अक्षर। इन्हें नीचे समझाया गया है:

और: यह पॉइंटर्स की एक सरणी है जो पर्यावरण चर को इंगित करती है और नई लोड की गई प्रक्रिया को स्पष्ट रूप से पारित कर दी जाती है।

NS: l कमांड लाइन तर्कों के लिए फ़ंक्शन के लिए एक सूची पास की गई है

पी: p पथ पर्यावरण चर है जो प्रक्रिया में लोड किए जाने वाले तर्क के रूप में पारित फ़ाइल को खोजने में मदद करता है।

वी: v कमांड लाइन तर्कों के लिए है। इन्हें फ़ंक्शन के पॉइंटर्स की एक सरणी के रूप में पारित किया जाता है।

निष्पादन का उपयोग क्यों किया जाता है?

निष्पादन का उपयोग तब किया जाता है जब उपयोगकर्ता उसी प्रक्रिया में एक नई फ़ाइल या प्रोग्राम लॉन्च करना चाहता है।

निष्पादन का आंतरिक कार्य

निष्पादन के कार्य को समझने के लिए निम्नलिखित बिंदुओं पर विचार करें:

  1. वर्तमान प्रक्रिया छवि को एक नई प्रक्रिया छवि के साथ अधिलेखित कर दिया गया है।
  2. नई प्रक्रिया छवि वह है जिसे आपने निष्पादन तर्क के रूप में पारित किया है
  3. वर्तमान में चल रही प्रक्रिया समाप्त हो गई है
  4. नई प्रक्रिया छवि में समान प्रक्रिया आईडी, समान वातावरण और समान फ़ाइल डिस्क्रिप्टर है (क्योंकि प्रक्रिया को प्रतिस्थापित नहीं किया गया है प्रक्रिया छवि को बदल दिया गया है)
  5. CPU स्टेट और वर्चुअल मेमोरी प्रभावित होती है। वर्तमान प्रक्रिया छवि की वर्चुअल मेमोरी मैपिंग को नई प्रक्रिया छवि की वर्चुअल मेमोरी से बदल दिया जाता है।

निष्पादन परिवार के कार्यों के सिंटैक्स:

निष्पादन के प्रत्येक फ़ंक्शन के लिए सिंटैक्स निम्नलिखित हैं:

int execl(const char* path, const char* arg,…)
int execlp(const char* file, const char* arg,…)
int execle(const char* path, const char* arg,…, char* const envp[])
int execv (कॉन्स्ट चार * पथ, कॉन्स चार * argv [])
int execvp (कॉन्स्ट चार * फ़ाइल, कॉन्स चार * argv [])
int execvpe(const char* file, const char* argv[], char *const envp[])

विवरण:

इन कार्यों का रिटर्न प्रकार Int है। जब प्रक्रिया छवि को सफलतापूर्वक बदल दिया जाता है तो कॉलिंग फ़ंक्शन पर कुछ भी वापस नहीं किया जाता है क्योंकि इसे कॉल करने वाली प्रक्रिया अब नहीं चल रही है। लेकिन अगर कोई त्रुटि है -1 वापस कर दिया जाएगा। यदि कोई त्रुटि होती है तो त्रुटिपूर्ण सेट है।

वाक्य रचना में:

  1. पथ फ़ाइल का पूरा पथ नाम निर्दिष्ट करने के लिए प्रयोग किया जाता है जिसे निष्पादित किया जाना है।
  1. गुस्सा पारित तर्क है। यह वास्तव में उस फ़ाइल का नाम है जिसे प्रक्रिया में निष्पादित किया जाएगा। अधिकांश बार आर्ग और पथ का मान समान होता है।
  1. कास्ट चार* arg कार्यों में execl (), execlp () और execle () को arg0, arg1, arg2,…, argn के रूप में माना जाता है। यह मूल रूप से पॉइंटर्स की एक सूची है जो टर्मिनेटेड स्ट्रिंग्स को शून्य करता है। यहां पहला तर्क फ़ाइल नाम को इंगित करता है जिसे बिंदु 2 में वर्णित अनुसार निष्पादित किया जाएगा।
  1. एनवीपी एक सरणी है जिसमें पॉइंटर्स होते हैं जो पर्यावरण चर को इंगित करते हैं।
  1. फ़ाइल पथ नाम निर्दिष्ट करने के लिए प्रयोग किया जाता है जो नई प्रक्रिया छवि फ़ाइल के पथ की पहचान करेगा।
  1. निष्पादन कॉल के कार्य जो समाप्त होते हैं और नई प्रक्रिया छवि के लिए पर्यावरण को बदलने के लिए उपयोग किया जाता है। ये फ़ंक्शन तर्क का उपयोग करके पर्यावरण सेटिंग की सूची पास करते हैं एनवीपी . यह तर्क वर्णों की एक सरणी है जो शून्य समाप्त स्ट्रिंग को इंगित करता है और पर्यावरण चर को परिभाषित करता है।

कार्यकारी परिवार के कार्यों का उपयोग करने के लिए, आपको अपने सी प्रोग्राम में निम्नलिखित शीर्षलेख फ़ाइल शामिल करने की आवश्यकता है:

#शामिल

उदाहरण 1: सी प्रोग्राम में निष्पादन सिस्टम कॉल का उपयोग करना

निम्नलिखित उदाहरण पर विचार करें जिसमें हमने लिनक्स, उबंटू में सी प्रोग्रामिंग में निष्पादन सिस्टम कॉल का उपयोग किया है: हमारे यहां दो सी फाइलें हैं example.c और hello.c:

example.c

कोड:

#शामिल
#शामिल
#शामिल
NSमुख्य(NSएर्गसी, char *अर्जीवी[])
{
printf ('example.c = %d . का पीआईडीएन',गेटपीड());
char *args[] = {'नमस्ते', 'सी', 'प्रोग्रामिंग',शून्य};
कार्यकारी('।/नमस्ते',args);
printf ('वापस example.c' पर);
वापसी 0;
}

नमस्ते सी

कोड:

#शामिल
#शामिल
#शामिल
NSमुख्य(NSएर्गसी, char *अर्जीवी[])
{
printf ('हम Hello.c . में हैंएन');
printf ('हैलो.सी का पीआईडी ​​=%dएन',गेटपीड());
वापसी 0;
}

आउटपुट:

उदाहरण का पीआईडी। सी = 4733
हम Hello.c . में हैं
hello.c का PID = 4733

उपरोक्त उदाहरण में हमारे पास example.c फ़ाइल और hello.c फ़ाइल है। उदाहरण .c फ़ाइल में सबसे पहले हमने वर्तमान प्रक्रिया की आईडी मुद्रित की है (फ़ाइल example.c वर्तमान प्रक्रिया में चल रही है)। फिर अगली पंक्ति में हमने कैरेक्टर पॉइंटर्स की एक सरणी बनाई है। इस सरणी का अंतिम तत्व समाप्ति बिंदु के रूप में NULL होना चाहिए।

फिर हमने फ़ंक्शन execv() का उपयोग किया है जो फ़ाइल नाम और वर्ण सूचक सरणी को इसके तर्क के रूप में लेता है। यहां यह ध्यान दिया जाना चाहिए कि हमने फ़ाइल के नाम के साथ ./ का उपयोग किया है, यह फ़ाइल का पथ निर्दिष्ट करता है। चूंकि फ़ाइल उस फ़ोल्डर में है जहां example.c रहता है इसलिए पूर्ण पथ निर्दिष्ट करने की कोई आवश्यकता नहीं है।

जब execv() फ़ंक्शन को कॉल किया जाता है, तो हमारी प्रक्रिया छवि को अब बदल दिया जाएगा फ़ाइल example.c प्रक्रिया में नहीं है लेकिन फ़ाइल hello.c प्रक्रिया में है। यह देखा जा सकता है कि प्रक्रिया आईडी समान है चाहे hello.c प्रक्रिया छवि हो या example.c प्रक्रिया छवि है क्योंकि प्रक्रिया समान है और प्रक्रिया छवि केवल बदली जाती है।

फिर हमारे पास यहां ध्यान देने योग्य एक और बात है जो कि execv() के निष्पादित नहीं होने के बाद प्रिंटफ () स्टेटमेंट है। ऐसा इसलिए है क्योंकि एक बार नई प्रक्रिया छवि को बदलने के बाद नियंत्रण पुरानी प्रक्रिया छवि पर वापस नहीं लौटाया जाता है। नियंत्रण केवल कॉलिंग फ़ंक्शन पर वापस आता है जब प्रक्रिया छवि को बदलना असफल होता है। (इस मामले में वापसी मूल्य -1 है)।

कांटा () और निष्पादन () सिस्टम कॉल के बीच अंतर:

फोर्क() सिस्टम कॉल का उपयोग चल रही प्रक्रिया की सटीक प्रतिलिपि बनाने के लिए किया जाता है और बनाई गई प्रतिलिपि बाल प्रक्रिया है और चलने की प्रक्रिया मूल प्रक्रिया है। जबकि, एक नई प्रक्रिया छवि के साथ एक प्रक्रिया छवि को बदलने के लिए निष्पादन () सिस्टम कॉल का उपयोग किया जाता है। इसलिए निष्पादन () सिस्टम कॉल में माता-पिता और बच्चे की प्रक्रियाओं की कोई अवधारणा नहीं है।

फोर्क () सिस्टम कॉल में माता-पिता और बच्चे की प्रक्रियाओं को एक ही समय में निष्पादित किया जाता है। लेकिन निष्पादन () सिस्टम कॉल में, यदि प्रक्रिया छवि का प्रतिस्थापन सफल होता है, तो नियंत्रण उस स्थान पर वापस नहीं आता जहां निष्पादन फ़ंक्शन को कॉल किया गया था, बल्कि यह नई प्रक्रिया को निष्पादित करेगा। कोई त्रुटि होने पर ही नियंत्रण वापस स्थानांतरित किया जाएगा।

उदाहरण 2: कांटा () और निष्पादन () सिस्टम कॉल का संयोजन

निम्नलिखित उदाहरण पर विचार करें जिसमें हमने एक ही प्रोग्राम में फोर्क () और एक्ज़ेक () सिस्टम कॉल दोनों का उपयोग किया है:

example.c

कोड:

#शामिल
#शामिल
#शामिल
NSमुख्य(NSएर्गसी, char *अर्जीवी[])
{
printf ('example.c = %d . का पीआईडीएन',गेटपीड());
pid_t p;
पी=कांटा();
अगर(पी== -1)
{
printf ('फोर्क ()' को कॉल करते समय एक त्रुटि हुई);
}
अगर(पी==0)
{
printf ('हम बच्चे की प्रक्रिया में हैं'एन');
printf ('बाल प्रक्रिया से hello.c को कॉल करना'एन');
char *args[] = {'नमस्ते', 'सी', 'प्रोग्रामिंग',शून्य};
कार्यकारी('।/नमस्ते',args);
}
अन्यथा
{
printf ('हम मूल प्रक्रिया में हैं');
}
वापसी 0;
}

नमस्ते सी:

कोड:

#शामिल
#शामिल
#शामिल
NSमुख्य(NSएर्गसी, char *अर्जीवी[])
{
printf ('हम Hello.c . में हैंएन');
printf ('हैलो.सी का पीआईडी ​​=%dएन',गेटपीड());
वापसी 0;
}

आउटपुट:

उदाहरण का पीआईडी। सी = 4790
हम मूल प्रक्रिया में हैं
हम बाल प्रक्रिया में हैं
चाइल्ड प्रोसेस से hello.c को कॉल करना
हम hello.c . में हैं
hello.c का PID = 4791

इस उदाहरण में हमने फोर्क () सिस्टम कॉल का उपयोग किया है। जब चाइल्ड प्रोसेस बनाया जाता है तो 0 को p को असाइन किया जाएगा और फिर हम चाइल्ड प्रोसेस में चले जाएंगे। अब बयानों का ब्लॉक if(p==0) के साथ निष्पादित किया जाएगा। एक संदेश प्रदर्शित होता है और हमने execv() सिस्टम कॉल का उपयोग किया है और वर्तमान चाइल्ड प्रोसेस इमेज जो कि example.c है, को hello.c से बदल दिया जाएगा। execv() कॉल से पहले बच्चे और माता-पिता की प्रक्रियाएं समान थीं।

यह देखा जा सकता है कि example.c और hello.c का PID अब अलग है। ऐसा इसलिए है क्योंकि example.c पैरेंट प्रोसेस इमेज है और hello.c चाइल्ड प्रोसेस इमेज है।