Výukový program Linux System Call s C

Linux System Call Tutorial With C



V našom poslednom článku o Systémové hovory Linuxu 'Definoval som systémové volanie, diskutoval o dôvodoch, prečo by ich niekto mohol použiť v programe, a rozobral som ich výhody a nevýhody. Dokonca som uviedol stručný príklad pri montáži v rámci C. Ukázalo to pointu a popísalo, ako uskutočniť hovor, ale neurobilo nič produktívne. Nie je to úplne vzrušujúce vývojové cvičenie, ale ilustrovalo pointu.

V tomto článku použijeme skutočné systémové hovory na skutočnú prácu v našom programe C. Najprv skontrolujeme, či potrebujete použiť systémové volanie, a potom poskytneme príklad pomocou volania sendfile (), ktoré môže výrazne zlepšiť výkon kopírovania súborov. Nakoniec si prejdeme niekoľko bodov, ktoré si treba pamätať pri používaní systémových hovorov Linuxu.







Aj keď je to nevyhnutné, v určitom okamihu svojej kariéry vo vývoji C použijete systémové volanie, pokiaľ sa nezameriavate na vysoký výkon alebo na funkcie konkrétneho typu, o väčšinu z nich sa postará knižnica glibc a ďalšie základné knižnice zahrnuté vo veľkých distribúciách Linuxu tvoje potreby.



Štandardná knižnica glibc poskytuje multiplatformový, dobre testovaný rámec na vykonávanie funkcií, ktoré by inak vyžadovali systémové volania špecifické pre systém. Môžete napríklad čítať súbor s príkazmi fscanf (), fread (), getc () atď., Alebo môžete použiť systémové volanie read () Linux. Funkcie glibc poskytujú viac funkcií (tj. Lepšie spracovanie chýb, formátované IO atď.) A budú fungovať na akomkoľvek systéme, ktorý podporuje glibc.



Na druhej strane existujú situácie, kedy je nekompromisný výkon a presné prevedenie rozhodujúce. Obal, ktorý poskytuje fread (), zvýši réžiu, a hoci je malý, nie je úplne transparentný. Navyše možno nebudete chcieť ani potrebovať ďalšie funkcie, ktoré obal poskytuje. V takom prípade vám najlepšie poslúži systémový hovor.





Systémové volania môžete použiť aj na vykonávanie funkcií, ktoré zatiaľ glibc nepodporuje. Ak je vaša kópia glibc aktuálna, sotva to bude problém, ale vývoj na starších distribúciách s novšími jadrami môže vyžadovať túto techniku.

Teraz, keď ste si prečítali zrieknutie sa zodpovednosti, varovania a potenciálne obchádzky, poďme sa teraz vrhnúť na niekoľko praktických príkladov.



Na akom CPU sme?

Otázka, ktorú si väčšina programov pravdepodobne nemyslí položiť, ale napriek tomu je platná. Toto je príklad systémového volania, ktoré nemožno duplikovať pomocou glibc a nie je pokryté obalom glibc. V tomto kóde zavoláme hovor getcpu () priamo pomocou funkcie syscall (). Funkcia syscall funguje nasledovne:

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

Prvý argument, SYS_call, je definícia, ktorá predstavuje číslo systémového volania. Keď zahrniete sys/syscall.h, budú zahrnuté aj tieto. Prvá časť je SYS_ a druhá časť je názov systémového volania.

Argumenty pre výzvu idú do arg1, arg2 vyššie. Niektoré hovory vyžadujú viac argumentov a budú pokračovať v poradí zo svojej manuálnej stránky. Pamätajte si, že väčšina argumentov, najmä pre návraty, bude vyžadovať ukazovatele na pole alebo pamäť pridelenú prostredníctvom funkcie malloc.

príklad1.c

#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť

intHlavná() {

bez znamienkaCPU,uzol;

// Získať aktuálne jadro CPU a uzol NUMA prostredníctvom systémového volania
// Všimnite si, že toto nemá žiadny obal glibc, takže ho musíme nazvať priamo
syscall(SYS_getcpu, &CPU, &uzol,NULOVÝ);

// Zobrazenie informácií
printf („Tento program beží na jadre CPU %u a uzle %u %NUM. n n',CPU,uzol);

vrátiť sa 0;

}

Zostaviť a spustiť:

gcc príklad 1.c -o príklad1
./príklad 1

Ak chcete získať zaujímavejšie výsledky, môžete roztočiť vlákna prostredníctvom knižnice pthreads a potom zavolať túto funkciu a zistiť, na akom procesore vaše vlákno beží.

Sendfile: Vynikajúci výkon

Sendfile poskytuje vynikajúci príklad zvýšenia výkonu prostredníctvom systémových hovorov. Funkcia sendfile () kopíruje údaje z jedného deskriptora súboru do druhého. Namiesto použitia viacerých funkcií fread () a fwrite (), sendfile vykonáva prenos v priestore jadra, znižuje režijné náklady a tým zvyšuje výkon.

V tomto prípade skopírujeme 64 MB údajov z jedného súboru do druhého. V jednom teste použijeme štandardné metódy čítania/zápisu v štandardnej knižnici. V druhom prípade použijeme systémové hovory a volanie sendfile () na prenos týchto údajov z jedného miesta na druhé.

test1.c (glibc)

#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť

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

intHlavná() {

SÚBOR*zle, *koniec;

printf (' nI/O test s tradičnými funkciami glibc. n n');

// Chyťte vyrovnávaciu pamäť BUFFER_SIZE.
// Vyrovnávacia pamäť bude obsahovať náhodné údaje, ale to nás nezaujíma.
printf („Vyhradenie 64 MB vyrovnávacej pamäte:“);
char *nárazník= (char *) malloc (BUFFER_SIZE);
printf ('HOTOVÝ n');

// Napíšte buffer do fOut
printf („Zápis údajov do prvej vyrovnávacej pamäte:“);
zle= fopen (BUFFER_1, 'wb');
fwrite (nárazník, veľkosť(char),BUFFER_SIZE,zle);
fclose (zle);
printf ('HOTOVÝ n');

printf („Kopírovanie údajov z prvého súboru do druhého:“);
koniec= fopen (BUFFER_1, 'rb');
zle= fopen (BUFFER_2, 'wb');
čudák (nárazník, veľkosť(char),BUFFER_SIZE,koniec);
fwrite (nárazník, veľkosť(char),BUFFER_SIZE,zle);
fclose (koniec);
fclose (zle);
printf ('HOTOVÝ n');

printf („Uvoľňujúci buffer:“);
zadarmo (nárazník);
printf ('HOTOVÝ n');

printf („Odstraňovanie súborov:“);
odstrániť (BUFFER_1);
odstrániť (BUFFER_2);
printf ('HOTOVÝ n');

vrátiť sa 0;

}

test2.c (systémové hovory)

#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť
#zahrnúť

#define BUFFER_SIZE 67108864

intHlavná() {

intzle,koniec;

printf (' nI/O test s sendfile () a súvisiacimi systémovými hovormi. n n');

// Chyťte vyrovnávaciu pamäť BUFFER_SIZE.
// Vyrovnávacia pamäť bude obsahovať náhodné údaje, ale to nás nezaujíma.
printf („Vyhradenie 64 MB vyrovnávacej pamäte:“);
char *nárazník= (char *) malloc (BUFFER_SIZE);
printf ('HOTOVÝ n');


// Napíšte buffer do fOut
printf („Zápis údajov do prvej vyrovnávacej pamäte:“);
zle=otvorené('buffer1',O_RDONLY);
písať(zle, &nárazník,BUFFER_SIZE);
Zavrieť(zle);
printf ('HOTOVÝ n');

printf („Kopírovanie údajov z prvého súboru do druhého:“);
koniec=otvorené('buffer1',O_RDONLY);
zle=otvorené('buffer2',O_RDONLY);
poslať súbor(zle,koniec, 0,BUFFER_SIZE);
Zavrieť(koniec);
Zavrieť(zle);
printf ('HOTOVÝ n');

printf („Uvoľňujúci buffer:“);
zadarmo (nárazník);
printf ('HOTOVÝ n');

printf („Odstraňovanie súborov:“);
odpojiť('buffer1');
odpojiť('buffer2');
printf ('HOTOVÝ n');

vrátiť sa 0;

}

Zostavenie a spustenie testov 1 a 2

Na zostavenie týchto príkladov budete potrebovať vývojové nástroje nainštalované vo vašej distribúcii. Na Debian a Ubuntu to môžete nainštalovať pomocou:

výstižnýInštaláciastavebné náležitosti

Potom skompilovajte pomocou:

gcctest1.c-alebotest 1&& gcctest2.c-alebotest 2

Ak chcete spustiť oboje a otestovať výkon, spustite:

čas./test 1&& čas./test 2

Mali by ste získať tieto výsledky:

I/O test s tradičnými funkciami glibc.

Vyhradenie 64 MB vyrovnávacej pamäte: HOTOVO
Zápis údajov do prvej vyrovnávacej pamäte: HOTOVO
Kopírovanie údajov z prvého súboru do druhého: HOTOVO
Uvoľňovací buffer: HOTOVO
Odstraňovanie súborov: HOTOVO
skutočných 0 m, 0,397 s
používateľ 0 mil. 000 s
sys 0m0,203s
I/O test s sendfile () a súvisiacimi systémovými hovormi.
Vyhradenie 64 MB vyrovnávacej pamäte: HOTOVO
Zápis údajov do prvej vyrovnávacej pamäte: HOTOVO
Kopírovanie údajov z prvého súboru do druhého: HOTOVO
Uvoľňovací buffer: HOTOVO
Odstraňovanie súborov: HOTOVO
skutočných 0 m0,019 s
používateľ 0 mil. 000 s
sys 0m0,016s

Ako vidíte, kód, ktorý používa systémové hovory, beží oveľa rýchlejšie ako ekvivalent glibc.

Veci na zapamätanie

Systémové hovory môžu zvýšiť výkon a poskytnúť ďalšie funkcie, ale nie sú bez ich nevýhod. Budete musieť zvážiť výhody, ktoré systémové hovory prinášajú, proti nedostatočnej prenosnosti platformy a niekedy aj zníženej funkčnosti v porovnaní s funkciami knižnice.

Pri použití niektorých systémových volaní musíte dbať na to, aby ste používali funkcie vrátené zo systémových hovorov, a nie z funkcií knižnice. Štruktúra FILE použitá pre funkcie fopen (), fread (), fwrite () a fclose () od glibc nie je rovnaká ako číslo deskriptora súboru zo systémového volania open () (vrátené ako celé číslo). Ich miešanie môže viesť k problémom.

Volanie systému Linux má vo všeobecnosti menej nárazníkových pruhov ako funkcie glibc. Aj keď je pravda, že systémové hovory majú určité spracovanie a hlásenie chýb, podrobnejšie funkcie získate z funkcie glibc.

A na záver slovo o bezpečnosti. Systém volá priamo s jadrom. Jadro Linuxu má rozsiahlu ochranu pred vylomením z užívateľskej oblasti, existujú však neobjavené chyby. Neverte, že systémové volanie overí váš vstup alebo vás izoluje od bezpečnostných problémov. Je rozumné zabezpečiť, aby údaje, ktoré odovzdáte systémovému hovoru, boli dezinfikované. Prirodzene, je to dobrá rada pre akékoľvek volanie API, ale pri práci s jadrom nemôžete byť opatrní.

Dúfam, že ste si užili tento hlbší ponor do krajiny systémových hovorov Linuxu. Úplný zoznam systémových hovorov systému Linux nájdete v našom hlavnom zozname.