सी . के साथ लिनक्स सिस्टम कॉल ट्यूटोरियल

Linux System Call Tutorial With C



हमारे पिछले लेख में लिनक्स सिस्टम कॉल , मैंने एक सिस्टम कॉल को परिभाषित किया, उन कारणों पर चर्चा की जो एक प्रोग्राम में उनका उपयोग कर सकते हैं, और उनके फायदे और नुकसान में तल्लीन हो गए। मैंने सी के भीतर असेंबली में एक संक्षिप्त उदाहरण भी दिया। इसने बिंदु को चित्रित किया और बताया कि कॉल कैसे करें, लेकिन कुछ भी उत्पादक नहीं था। वास्तव में एक रोमांचक विकास अभ्यास नहीं है, लेकिन इसने बिंदु को स्पष्ट कर दिया है।

इस लेख में, हम अपने सी प्रोग्राम में वास्तविक कार्य करने के लिए वास्तविक सिस्टम कॉल का उपयोग करने जा रहे हैं। सबसे पहले, हम समीक्षा करेंगे कि क्या आपको सिस्टम कॉल का उपयोग करने की आवश्यकता है, फिर सेंडफाइल () कॉल का उपयोग करके एक उदाहरण प्रदान करें जो फ़ाइल कॉपी प्रदर्शन में नाटकीय रूप से सुधार कर सकता है। अंत में, हम Linux सिस्टम कॉल का उपयोग करते समय याद रखने के लिए कुछ बिंदुओं पर जाएंगे।







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



ग्लिबैक मानक पुस्तकालय कार्यों को निष्पादित करने के लिए एक क्रॉस-प्लेटफ़ॉर्म, अच्छी तरह से परीक्षण किया गया ढांचा प्रदान करता है जिसे अन्यथा सिस्टम-विशिष्ट सिस्टम कॉल की आवश्यकता होती है। उदाहरण के लिए, आप fscanf (), fread (), getc (), आदि के साथ एक फ़ाइल पढ़ सकते हैं, या आप रीड () Linux सिस्टम कॉल का उपयोग कर सकते हैं। glibc फ़ंक्शन अधिक सुविधाएँ प्रदान करते हैं (अर्थात बेहतर त्रुटि प्रबंधन, स्वरूपित IO, आदि) और किसी भी सिस्टम glibc समर्थन पर काम करेंगे।



दूसरी ओर, ऐसे समय होते हैं जब समझौता न करने वाला प्रदर्शन और सटीक निष्पादन महत्वपूर्ण होता है। रैपर जो फ़्रेड () प्रदान करता है, वह ओवरहेड जोड़ने वाला है, और हालांकि मामूली, पूरी तरह से पारदर्शी नहीं है। इसके अतिरिक्त, हो सकता है कि आपको रैपर द्वारा प्रदान की जाने वाली अतिरिक्त सुविधाओं की आवश्यकता न हो या आवश्यकता न हो। उस स्थिति में, आपको सिस्टम कॉल के साथ सबसे अच्छी सेवा दी जाती है।





आप सिस्टम कॉल का उपयोग ऐसे कार्यों को करने के लिए भी कर सकते हैं जो अभी तक glibc द्वारा समर्थित नहीं हैं। यदि ग्लिबक की आपकी प्रति अप टू डेट है, तो यह शायद ही कोई समस्या होगी, लेकिन नए कर्नेल के साथ पुराने वितरण पर विकास के लिए इस तकनीक की आवश्यकता हो सकती है।

अब जब आपने अस्वीकरण, चेतावनियां और संभावित चक्कर पढ़ लिए हैं, तो अब कुछ व्यावहारिक उदाहरणों पर गौर करते हैं।



हम किस सीपीयू पर हैं?

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

सिस्कल(SYS_call,arg1,arg2,...);

पहला तर्क, SYS_call, एक परिभाषा है जो सिस्टम कॉल की संख्या को दर्शाता है। जब आप sys/syscall.h शामिल करते हैं, तो ये शामिल होते हैं। पहला भाग SYS_ है और दूसरा भाग सिस्टम कॉल का नाम है।

कॉल के लिए तर्क ऊपर arg1, arg2 में जाते हैं। कुछ कॉलों के लिए अधिक तर्कों की आवश्यकता होती है, और वे अपने मैन पेज से क्रम में जारी रहेंगे। याद रखें कि अधिकांश तर्क, विशेष रूप से रिटर्न के लिए, पॉइंटर्स को चार सरणी या मॉलोक फ़ंक्शन के माध्यम से आवंटित स्मृति की आवश्यकता होगी।

example1.c

#शामिल
#शामिल
#शामिल
#शामिल

NSमुख्य() {

अहस्ताक्षरितसी पी यू,नोड;

// सिस्टम कॉल के माध्यम से वर्तमान CPU कोर और NUMA नोड प्राप्त करें
// ध्यान दें कि इसमें कोई ग्लिबक आवरण नहीं है, इसलिए हमें इसे सीधे कॉल करना चाहिए
सिस्कल(SYS_getcpu, औरसी पी यू, औरनोड,शून्य);

// जानकारी प्रदर्शित करें
printf ('यह प्रोग्राम CPU कोर %u और NUMA नोड %u पर चल रहा है।एनएन',सी पी यू,नोड);

वापसी 0;

}

संकलन और चलाने के लिए:

जीसीसी उदाहरण1.सी -ओ उदाहरण1
./उदाहरण 1

अधिक दिलचस्प परिणामों के लिए, आप थ्रेड्स को पर्थ्रेड लाइब्रेरी के माध्यम से स्पिन कर सकते हैं और फिर इस फ़ंक्शन को यह देखने के लिए कॉल कर सकते हैं कि आपका थ्रेड किस प्रोसेसर पर चल रहा है।

सेंडफाइल: सुपीरियर परफॉर्मेंस

Sendfile सिस्टम कॉल के माध्यम से प्रदर्शन बढ़ाने का एक उत्कृष्ट उदाहरण प्रदान करता है। Sendfile () फ़ंक्शन डेटा को एक फ़ाइल डिस्क्रिप्टर से दूसरे में कॉपी करता है। एकाधिक fread() और fwrite() फ़ंक्शंस का उपयोग करने के बजाय, sendfile कर्नेल स्पेस में स्थानांतरण करता है, ओवरहेड को कम करता है और इस प्रकार प्रदर्शन में वृद्धि करता है।

इस उदाहरण में, हम एक फ़ाइल से दूसरी फ़ाइल में 64 एमबी डेटा कॉपी करने जा रहे हैं। एक परीक्षण में, हम मानक पुस्तकालय में मानक पढ़ने / लिखने के तरीकों का उपयोग करने जा रहे हैं। दूसरे में, हम इस डेटा को एक स्थान से दूसरे स्थान पर विस्फोट करने के लिए सिस्टम कॉल और सेंडफाइल () कॉल का उपयोग करेंगे।

test1.c (ग्लिबक)

#शामिल
#शामिल
#शामिल
#शामिल

# परिभाषित करें BUFFER_SIZE 67108864
# परिभाषित करें BUFFER_1 'बफर1'
# परिभाषित करें BUFFER_2 'बफर2'

NSमुख्य() {

फ़ाइल*गलत, *समाप्त;

printf ('एनI/O परीक्षण पारंपरिक glibc फ़ंक्शन के साथ।एनएन');

// एक BUFFER_SIZE बफर लें।
// बफर में यादृच्छिक डेटा होगा लेकिन हमें इसकी परवाह नहीं है।
printf ('64 एमबी बफर आवंटित करना:');
char *बफर= (char *) मॉलोक (बफर आकार);
printf ('किया हुआएन');

// बफर को fOut . पर लिखें
printf ('पहले बफर में डेटा लिखना:');
गलत= फोपेन (बफर_1, 'डब्ल्यूबी');
fwrite (बफर, का आकार(char),बफर आकार,गलत);
fclose (गलत);
printf ('किया हुआएन');

printf ('पहली फ़ाइल से दूसरी फ़ाइल में डेटा की प्रतिलिपि बनाना:');
समाप्त= फोपेन (बफर_1, 'आरबी');
गलत= फोपेन (बफर_2, 'डब्ल्यूबी');
फ़्रेड (बफर, का आकार(char),बफर आकार,समाप्त);
fwrite (बफर, का आकार(char),बफर आकार,गलत);
fclose (समाप्त);
fclose (गलत);
printf ('किया हुआएन');

printf ('मुक्त बफर:');
नि: शुल्क (बफर);
printf ('किया हुआएन');

printf ('फ़ाइलें हटाना:');
हटाना (बफर_1);
हटाना (बफर_2);
printf ('किया हुआएन');

वापसी 0;

}

test2.c (सिस्टम कॉल)

#शामिल
#शामिल
#शामिल
#शामिल
#शामिल
#शामिल
#शामिल
#शामिल
#शामिल

# परिभाषित करें BUFFER_SIZE 67108864

NSमुख्य() {

NSगलत,समाप्त;

printf ('एनSendfile () और संबंधित सिस्टम कॉल के साथ I/O परीक्षण।एनएन');

// एक BUFFER_SIZE बफर लें।
// बफर में यादृच्छिक डेटा होगा लेकिन हमें इसकी परवाह नहीं है।
printf ('64 एमबी बफर आवंटित करना:');
char *बफर= (char *) मॉलोक (बफर आकार);
printf ('किया हुआएन');


// बफर को fOut . पर लिखें
printf ('पहले बफर में डेटा लिखना:');
गलत=खोलना('बफर1',O_RDONLY);
लिखो(गलत, औरबफर,बफर आकार);
बंद करे(गलत);
printf ('किया हुआएन');

printf ('पहली फ़ाइल से दूसरी फ़ाइल में डेटा की प्रतिलिपि बनाना:');
समाप्त=खोलना('बफर1',O_RDONLY);
गलत=खोलना('बफर2',O_RDONLY);
लेख्यपत्र भेज दें(गलत,समाप्त, 0,बफर आकार);
बंद करे(समाप्त);
बंद करे(गलत);
printf ('किया हुआएन');

printf ('मुक्त बफर:');
नि: शुल्क (बफर);
printf ('किया हुआएन');

printf ('फ़ाइलें हटाना:');
अनलिंक('बफर1');
अनलिंक('बफर2');
printf ('किया हुआएन');

वापसी 0;

}

परीक्षण 1 और 2 का संकलन और चलाना

इन उदाहरणों को बनाने के लिए, आपको अपने वितरण पर स्थापित विकास उपकरण की आवश्यकता होगी। डेबियन और उबंटू पर, आप इसे इसके साथ स्थापित कर सकते हैं:

उपयुक्तइंस्टॉलनिर्माण-आवश्यक

फिर इसके साथ संकलित करें:

जीसीसीtest1.c-याटेस्ट1&& जीसीसीtest2.c-याटेस्ट2

दोनों को चलाने और प्रदर्शन का परीक्षण करने के लिए, दौड़ें:

समय./टेस्ट1&& समय./टेस्ट2

आपको इस तरह के परिणाम मिलने चाहिए:

I/O परीक्षण पारंपरिक glibc फ़ंक्शन के साथ।

64 एमबी बफर आवंटित करना: हो गया
पहले बफ़र को डेटा लिखना: हो गया
पहली फ़ाइल से दूसरी फ़ाइल में डेटा कॉपी करना: हो गया
मुक्त बफर: हो गया
फ़ाइलें हटाना: हो गया
वास्तविक 0m0.397s
उपयोगकर्ता 0m0.000s
sys 0m0.203s
Sendfile () और संबंधित सिस्टम कॉल के साथ I/O परीक्षण।
64 एमबी बफर आवंटित करना: हो गया
पहले बफ़र को डेटा लिखना: हो गया
पहली फ़ाइल से दूसरी फ़ाइल में डेटा कॉपी करना: हो गया
मुक्त बफर: हो गया
फ़ाइलें हटाना: हो गया
वास्तविक 0m0.019s
उपयोगकर्ता 0m0.000s
sys 0m0.016s

जैसा कि आप देख सकते हैं, सिस्टम कॉल का उपयोग करने वाला कोड ग्लिबैक समकक्ष की तुलना में बहुत तेज चलता है।

याद रखने वाली चीज़ें

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

कुछ सिस्टम कॉल का उपयोग करते समय, आपको लाइब्रेरी फ़ंक्शन के बजाय सिस्टम कॉल से लौटाए गए संसाधनों का उपयोग करने पर ध्यान देना चाहिए। उदाहरण के लिए, glibc के fopen (), fread (), fwrite (), और fclose () फ़ंक्शन के लिए उपयोग की जाने वाली FILE संरचना ओपन () सिस्टम कॉल (एक पूर्णांक के रूप में लौटाई गई) से फ़ाइल डिस्क्रिप्टर संख्या के समान नहीं है। इन्हें मिलाने से समस्या हो सकती है।

सामान्य तौर पर, Linux सिस्टम कॉल में glibc फ़ंक्शन की तुलना में कम बम्पर लेन होती है। हालांकि यह सच है कि सिस्टम कॉल में कुछ त्रुटि प्रबंधन और रिपोर्टिंग होती है, आपको ग्लिबैक फ़ंक्शन से अधिक विस्तृत कार्यक्षमता प्राप्त होगी।

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

मुझे आशा है कि आपने लिनक्स सिस्टम कॉल की भूमि में इस गहरे गोता का आनंद लिया। Linux सिस्टम कॉल की पूरी सूची के लिए, हमारी मास्टर सूची देखें।