Tutorial ng Call System ng Linux na may C

Linux System Call Tutorial With C



Sa aming huling artikulo sa Mga Tawag sa System ng Linux , Tinukoy ko ang isang tawag sa system, tinalakay ang mga kadahilanang maaaring gamitin ito ng isang tao sa isang programa, at sinaliksik ang kanilang mga kalamangan at kalamangan. Nagbigay pa ako ng isang maikling halimbawa sa pagpupulong sa loob ng C. Inilarawan nito ang punto at inilarawan kung paano tumawag, ngunit walang nagawang mabunga. Hindi eksaktong isang kapanapanabik na ehersisyo sa pag-unlad, ngunit inilarawan nito ang punto.

Sa artikulong ito, gagamitin namin ang aktwal na mga tawag sa system upang gumawa ng tunay na trabaho sa aming C program. Una, susuriin namin kung kailangan mong gumamit ng isang tawag sa system, pagkatapos ay magbigay ng isang halimbawa gamit ang sendfile () na tawag na maaaring mapabuti ang pagganap ng pag-kopya ng file. Sa wakas, tatalakayin natin ang ilang mga puntos na dapat tandaan habang gumagamit ng mga tawag sa system ng Linux.







Habang hindi maiiwasan gagamit ka ng isang tawag sa system sa ilang mga punto sa iyong karera sa pag-unlad ng C, maliban kung tina-target mo ang mataas na pagganap o isang partikular na pag-andar ng uri, ang glibc library at iba pang pangunahing mga aklatan na kasama sa mga pangunahing pamamahagi ng Linux ay mag-aalaga ng karamihan ng ang mga pangangailangan mo.



Nagbibigay ang glibc standard library ng isang cross-platform, nasubukan nang maayos na balangkas upang maisagawa ang mga pagpapaandar na maaaring mangailangan ng mga tawag sa system na tukoy sa system. Halimbawa, maaari mong basahin ang isang file na may fscanf (), fread (), getc (), atbp. O maaari mong gamitin ang nabasa () na tawag sa system ng Linux. Ang mga pagpapaandar ng glibc ay nagbibigay ng higit pang mga tampok (hal. Mas mahusay na paghawak ng error, naka-format na IO, atbp.) At gagana sa anumang mga suporta ng system na glibc.



Sa kabilang banda, may mga oras kung saan kritikal ang hindi kompromisong pagganap at eksaktong pagpapatupad. Ang pambalot na ibinibigay () na ibinibigay () ay magdaragdag ng overhead, at bagaman menor de edad, ay hindi ganap na malinaw. Bilang karagdagan, maaaring hindi mo gusto o kailangan ang mga karagdagang tampok na ibinibigay ng balot. Sa kasong iyon, mas mahusay kang ihatid sa isang tawag sa system.





Maaari mo ring gamitin ang mga tawag sa system upang magsagawa ng mga pagpapaandar na hindi pa suportado ng glibc. Kung napapanahon ang iyong kopya ng glibc, malamang na hindi ito maging isyu, ngunit ang pag-unlad sa mas matandang pamamahagi na may mas bagong mga kernel ay maaaring mangailangan ng pamamaraang ito.

Ngayon na nabasa mo na ang mga disclaimer, babala, at mga potensyal na detour, ngayon ay maghukay tayo sa ilang mga praktikal na halimbawa.



Ano ang CPU Nasa Kami?

Isang tanong na marahil ay hindi iniisip ng karamihan sa mga programa na magtanong, ngunit may bisa pa rin. Ito ay isang halimbawa ng isang tawag sa system na hindi maaaring madoble ng glibc at hindi natatakpan ng isang glibc wrapper. Sa code na ito, tatawagan namin ang tawag na getcpu () nang direkta sa pamamagitan ng pagpapaandar ng syscall (). Gumagana ang pagpapaandar ng syscall tulad ng sumusunod:

syscall(SYS_call,arg1,arg2,...);

Ang unang argumento, SYS_call, ay isang kahulugan na kumakatawan sa bilang ng tawag sa system. Kapag isinama mo ang sys / syscall.h, kasama ang mga ito. Ang unang bahagi ay SYS_ at ang pangalawang bahagi ay ang pangalan ng tawag sa system.

Ang mga argumento para sa tawag ay papunta sa arg1, arg2 sa itaas. Ang ilang mga tawag ay nangangailangan ng mas maraming mga argumento, at magpapatuloy sila sa pagkakasunud-sunod mula sa kanilang pahina ng tao. Tandaan na ang karamihan sa mga argumento, lalo na para sa mga pagbabalik, ay mangangailangan ng mga pahiwatig sa char array o memorya na inilalaan sa pamamagitan ng pagpapaandar ng malloc.

halimbawa1.c

# isama
# isama
# isama
# isama

intpangunahing() {

hindi pinirmahancpu,node;

// Kunin ang kasalukuyang CPU core at NUMA node sa pamamagitan ng system call
// Tandaan na wala itong glibc wrapper kaya dapat direktang tawagan natin ito
syscall(SYS_getcpu, &cpu, &node,WALA);

// Ipakita ang impormasyon
printf ('Ang program na ito ay tumatakbo sa CPU core% u at NUMA node% u. n n',cpu,node);

bumalik ka 0;

}

Upang mag-ipon at magpatakbo:

gcc halimbawa1.c -o halimbawa1
./halimbawa1

Para sa higit pang mga kagiliw-giliw na resulta, maaari kang magsulid ng mga thread sa pamamagitan ng library ng pthreads at pagkatapos ay tawagan ang pagpapaandar na ito upang makita kung aling processor ang tumatakbo sa iyong thread.

Sendfile: Superior Performance

Nagbibigay ang Sendfile ng mahusay na halimbawa ng pagpapahusay ng pagganap sa pamamagitan ng mga tawag sa system. Ang function na sendfile () ay kumopya ng data mula sa isang deskriptor ng file sa isa pa. Sa halip na gumamit ng maraming pag-andar ng fread () at fwrite (), isinasagawa ng sendfile ang paglipat sa puwang ng kernel, binabawasan ang overhead at dahil doon ay nadaragdagan ang pagganap.

Sa halimbawang ito, makokopya namin ang 64 MB ng data mula sa isang file patungo sa isa pa. Sa isang pagsubok, gagamitin namin ang karaniwang mga paraan ng pagbasa / pagsulat sa karaniwang silid aklatan. Sa isa pa, gagamit kami ng mga tawag sa system at ang sendfile () na tawag upang sabog ang data na ito mula sa isang lokasyon patungo sa isa pa.

test1.c (glibc)

# isama
# isama
# isama
# isama

# tukuyin ang BUFFER_SIZE 67108864
#define BUFFER_1 'buffer1'
# tukuyin ang BUFFER_2 'buffer2'

intpangunahing() {

FILE*mali, *magtapos;

printf (' nAng pagsubok sa I / O na may tradisyonal na mga pagpapaandar ng glibc. n n');

// Grab a BUFFER_SIZE buffer.
// Ang buffer ay magkakaroon ng random na data dito ngunit wala kaming pakialam doon.
printf ('Paglalaan ng buffer ng 64 MB:');
char *buffer= (char *) malloc (BUFFER_SIZE);
printf ('TAPOS NA n');

// Isulat ang buffer sa fOut
printf ('Pagsusulat ng data sa unang buffer:');
mali= magbukas (BUFFER_1, 'wb');
magsulat (buffer, sukat ng(char),BUFFER_SIZE,mali);
magsara (mali);
printf ('TAPOS NA n');

printf ('Kinokopya ang data mula sa unang file hanggang sa pangalawa:');
magtapos= magbukas (BUFFER_1, 'rb');
mali= magbukas (BUFFER_2, 'wb');
mag-ayos (buffer, sukat ng(char),BUFFER_SIZE,magtapos);
magsulat (buffer, sukat ng(char),BUFFER_SIZE,mali);
magsara (magtapos);
magsara (mali);
printf ('TAPOS NA n');

printf ('Freeing buffer:');
libre (buffer);
printf ('TAPOS NA n');

printf ('Pagtanggal ng mga file:');
tanggalin (BUFFER_1);
tanggalin (BUFFER_2);
printf ('TAPOS NA n');

bumalik ka 0;

}

test2.c (tawag sa system)

# isama
# isama
# isama
# isama
# isama
# isama
# isama
# isama
# isama

# tukuyin ang BUFFER_SIZE 67108864

intpangunahing() {

intmali,magtapos;

printf (' nAng pagsubok sa I / O na may sendfile () at mga kaugnay na tawag sa system. n n');

// Grab a BUFFER_SIZE buffer.
// Ang buffer ay magkakaroon ng random na data dito ngunit wala kaming pakialam doon.
printf ('Paglalaan ng buffer ng 64 MB:');
char *buffer= (char *) malloc (BUFFER_SIZE);
printf ('TAPOS NA n');


// Isulat ang buffer sa fOut
printf ('Pagsusulat ng data sa unang buffer:');
mali=buksan('buffer1',O_RDONLY);
sumulat(mali, &buffer,BUFFER_SIZE);
malapit na(mali);
printf ('TAPOS NA n');

printf ('Kinokopya ang data mula sa unang file hanggang sa pangalawa:');
magtapos=buksan('buffer1',O_RDONLY);
mali=buksan('buffer2',O_RDONLY);
sendfile(mali,magtapos, 0,BUFFER_SIZE);
malapit na(magtapos);
malapit na(mali);
printf ('TAPOS NA n');

printf ('Freeing buffer:');
libre (buffer);
printf ('TAPOS NA n');

printf ('Pagtanggal ng mga file:');
i-unlink('buffer1');
i-unlink('buffer2');
printf ('TAPOS NA n');

bumalik ka 0;

}

Pagsasama-sama at Pagpapatakbo ng Mga Pagsubok 1 & 2

Upang maitayo ang mga halimbawang ito, kakailanganin mo ang mga tool sa pag-unlad na naka-install sa iyong pamamahagi. Sa Debian at Ubuntu, maaari mo itong mai-install sa:

apti-installmga kailangan sa pagbuo

Pagkatapos ay ipunin sa:

gccpagsubok1.c-o kayapagsubok1&& gccpagsubok2.c-o kayapagsubok2

Upang patakbuhin ang pareho at subukan ang pagganap, patakbuhin:

oras./pagsubok1&& oras./pagsubok2

Dapat kang makakuha ng mga resulta tulad nito:

Ang pagsubok sa I / O na may tradisyonal na mga pagpapaandar ng glibc.

Naglalaan ng buffer ng 64 MB: TAPOS
Pagsulat ng data sa unang buffer: TAPOS
Pagkopya ng data mula sa unang file patungo sa pangalawa: TAPOS
Nagpapalaya ng buffer: TAPOS
Pagtanggal ng mga file: TAPOS NA
tunay na 0m0.397s
gumagamit ng 0m0.000s
sys 0m0.203s
Ang pagsubok sa I / O na may sendfile () at mga kaugnay na tawag sa system.
Naglalaan ng buffer ng 64 MB: TAPOS
Pagsulat ng data sa unang buffer: TAPOS
Pagkopya ng data mula sa unang file patungo sa pangalawa: TAPOS
Nagpapalaya ng buffer: TAPOS
Pagtanggal ng mga file: TAPOS NA
tunay na 0m0.019s
gumagamit ng 0m0.000s
sys 0m0.016s

Tulad ng nakikita mo, ang code na gumagamit ng mga tawag sa system ay tumatakbo nang mas mabilis kaysa sa katumbas ng glibc.

Bagay na dapat alalahanin

Ang mga tawag sa system ay maaaring dagdagan ang pagganap at magbigay ng karagdagang pag-andar, ngunit hindi sila wala ng kanilang mga dehado. Susubukan mong timbangin ang mga benepisyo na ibinibigay ng mga tawag sa system laban sa kakulangan ng kakayahang dalhin sa platform at kung minsan ay binawasan ang pag-andar kumpara sa mga pagpapaandar sa library.

Kapag gumagamit ng ilang mga tawag sa system, dapat kang mag-ingat na magamit ang mga mapagkukunang ibinalik mula sa mga tawag sa system kaysa sa mga pagpapaandar sa library. Halimbawa, ang istrakturang FILE na ginamit para sa glibc's fopen (), fread (), fwrite (), at fclose () na mga function ay hindi pareho sa numero ng deskriptor ng file mula sa bukas () na tawag sa system (ibinalik bilang isang integer). Ang paghahalo ng mga ito ay maaaring humantong sa mga isyu.

Sa pangkalahatan, ang mga tawag sa system ng Linux ay may mas kaunting mga bumper lane kaysa sa mga pagpapaandar ng glibc. Bagaman totoo na ang mga tawag sa system ay may ilang paghawak sa error at pag-uulat, makakakuha ka ng mas detalyadong pagpapaandar mula sa isang pagpapaandar ng glibc.

At sa wakas, isang salita tungkol sa seguridad. Tawag ng system na direktang interface sa kernel. Ang Linux kernel ay mayroong malawak na proteksyon laban sa mga shenanigan mula sa lupain ng gumagamit, ngunit mayroon nang mga hindi natuklasan na mga bug. Huwag magtiwala na ang isang tawag sa system ay mapatunayan ang iyong pag-input o ihiwalay ka mula sa mga isyu sa seguridad. Ito ay matalino upang matiyak na ang data na iyong ipinasa sa isang tawag sa system ay nalinis. Naturally, magandang payo ito para sa anumang tawag sa API, ngunit hindi ka maaaring maging maingat kapag nagtatrabaho kasama ang kernel.

Inaasahan kong nasiyahan ka sa mas malalim na pagsisid sa lupain ng mga tawag sa system ng Linux. Para sa isang buong listahan ng Mga Tawag sa System ng Linux, tingnan ang aming master list.