Водич за системске позиве Линука са Ц

Linux System Call Tutorial With C



У нашем последњем чланку о Линук системски позиви , Дефинисао сам системски позив, разговарао о разлозима због којих их неко може користити у програму и удубио се у њихове предности и недостатке. Чак сам дао и кратак пример при састављању унутар Ц. То је илустровало поенту и описало како се упућује позив, али није учинило ништа продуктивно. Није баш узбудљива развојна вежба, али је илустровала поенту.

У овом чланку ћемо користити стварне системске позиве за прави посао у нашем Ц програму. Прво ћемо прегледати да ли требате да користите системски позив, а затим навести пример помоћу позива сендфиле () који може драматично побољшати перформансе копирања датотеке. Коначно, прећи ћемо на неке тачке које треба запамтити док користите системске позиве за Линук.







Иако је неизбежно да ћете у неком тренутку своје развојне каријере користити системски позив, осим ако не циљате високе перформансе или функционалност одређеног типа, библиотека глибц и друге основне библиотеке укључене у главне дистрибуције Линука ће се побринути за већину Ваше потребе.



Стандардна библиотека глибц пружа цросс-платформ, добро тестиран оквир за извршавање функција које би иначе захтевале системске позиве специфичне за систем. На пример, можете читати датотеку са фсцанф (), фреад (), гетц () итд., Или можете користити системски позив реад () Линук. Глибц функције пружају више функција (тј. Боље руковање грешкама, форматирани ИО, итд.) И радиће на било којој системској глибц подршци.



С друге стране, постоје тренуци у којима су бескомпромисне перформансе и тачно извршење критични. Омотач који фреад () пружа ће додати додатне трошкове, и иако је мањи, није потпуно транспарентан. Осим тога, можда нећете желети или вам требати додатне функције које омот пружа. У том случају најбоље ће вам послужити системски позив.





Системске позиве можете користити и за обављање функција које глибц још не подржава. Ако је ваша копија програма глибц ажурирана, то тешко да ће представљати проблем, али развој на старијим дистрибуцијама са новијим језгрима можда ће захтијевати ову технику.

Сада када сте прочитали одрицања од одговорности, упозорења и потенцијалне заобилазнице, сада ћемо се позабавити неким практичним примерима.



На ком смо ЦПУ -у?

Питање које већина програма вероватно не мисли да постави, али је ипак ваљано. Ово је пример системског позива који се не може дуплицирати са глибц и није прекривен омотом глибц. У овом коду ћемо позвати гетцпу () позив директно преко функције сисцалл (). Функција сисцалл ради на следећи начин:

сисцалл(СИС_цалл,арг1,арг2,...);

Први аргумент, СИС_цалл, је дефиниција која представља број системског позива. Када укључите сис/сисцалл.х, они су укључени. Први део је СИС_, а други део је назив системског позива.

Аргументи за позив иду у горе наведене арг1, арг2. Неки позиви захтевају више аргумената и наставиће се редом са своје странице за кориснике. Имајте на уму да ће већина аргумената, посебно за поврат, захтијевати показиваче за оглеђивање низа или меморију додијељену помоћу функције маллоц.

екампле1.ц

#инцлуде
#инцлуде
#инцлуде
#инцлуде

интглавни() {

непотписаноПроцесори,чвор;

// Добијте тренутно ЦПУ језгро и НУМА чвор путем системског позива
// Имајте на уму да ово нема глибц омот па га морамо позвати директно
сисцалл(СИС_гетцпу, &Процесори, &чвор,НУЛА);

// Приказ информација
принтф ('Овај програм ради на језгри процесора %у и НУМА чвору %у. н н',Процесори,чвор);

повратак 0;

}

Да компајлирате и покренете:

гцц пример1.ц -о пример1
./пример1

За занимљивије резултате, можете окретати нити путем библиотеке птхреадс, а затим позвати ову функцију да видите на ком процесору ваша нит ради.

Сендфиле: Врхунске перформансе

Сендфиле пружа одличан пример побољшања перформанси путем системских позива. Функција сендфиле () копира податке из једног дескриптора датотеке у други. Уместо да користи више фреад () и фврите () функција, сендфиле врши пренос у простору језгра, смањујући оптерећење и тиме повећавајући перформансе.

У овом примеру ћемо копирати 64 МБ података из једне датотеке у другу. У једном тесту ћемо користити стандардне методе читања/писања у стандардној библиотеци. У другом, користићемо системске позиве и позив сендфиле () за пребацивање ових података са једне локације на другу.

тест1.ц (глибц)

#инцлуде
#инцлуде
#инцлуде
#инцлуде

#дефине БУФФЕР_СИЗЕ 67108864
#дефине БУФФЕР_1 'буффер1'
#дефине БУФФЕР_2 'буффер2'

интглавни() {

ФИЛЕ*погрешно, *крај;

принтф (' нИ/О тест са традиционалним глибц функцијама. н н');

// Зграбите бафер БУФФЕР_СИЗЕ.
// Међуспремник ће имати насумичне податке, али нас то не занима.
принтф ('Додељивање међуспремника од 64 МБ:');
цхар *тампон= (цхар *) маллоц (БУФФЕР_СИЗЕ);
принтф ('ГОТОВО н');

// Напишите бафер у фОут
принтф ('Записивање података у први бафер:');
погрешно= фопен (БУФФЕР_1, 'вб');
фврите (тампон, величина(цхар),БУФФЕР_СИЗЕ,погрешно);
фцлосе (погрешно);
принтф ('ГОТОВО н');

принтф ('Копирање података из прве датотеке у другу:');
крај= фопен (БУФФЕР_1, 'рб');
погрешно= фопен (БУФФЕР_2, 'вб');
фреад (тампон, величина(цхар),БУФФЕР_СИЗЕ,крај);
фврите (тампон, величина(цхар),БУФФЕР_СИЗЕ,погрешно);
фцлосе (крај);
фцлосе (погрешно);
принтф ('ГОТОВО н');

принтф ('Ослобађање бафера:');
бесплатно (тампон);
принтф ('ГОТОВО н');

принтф ('Брисање датотека:');
уклонити (БУФФЕР_1);
уклонити (БУФФЕР_2);
принтф ('ГОТОВО н');

повратак 0;

}

тест2.ц (системски позиви)

#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде
#инцлуде

#дефине БУФФЕР_СИЗЕ 67108864

интглавни() {

интпогрешно,крај;

принтф (' нИ/О тест са сендфиле () и повезани системски позиви. н н');

// Зграбите бафер БУФФЕР_СИЗЕ.
// Међуспремник ће имати насумичне податке, али нас то не занима.
принтф ('Додељивање међуспремника од 64 МБ:');
цхар *тампон= (цхар *) маллоц (БУФФЕР_СИЗЕ);
принтф ('ГОТОВО н');


// Напишите бафер у фОут
принтф ('Записивање података у први бафер:');
погрешно=отворен('буффер1',О_РДОНЛИ);
писати(погрешно, &тампон,БУФФЕР_СИЗЕ);
Близу(погрешно);
принтф ('ГОТОВО н');

принтф ('Копирање података из прве датотеке у другу:');
крај=отворен('буффер1',О_РДОНЛИ);
погрешно=отворен('буффер2',О_РДОНЛИ);
сендфиле(погрешно,крај, 0,БУФФЕР_СИЗЕ);
Близу(крај);
Близу(погрешно);
принтф ('ГОТОВО н');

принтф ('Ослобађање бафера:');
бесплатно (тампон);
принтф ('ГОТОВО н');

принтф ('Брисање датотека:');
раскинути везу('буффер1');
раскинути везу('буффер2');
принтф ('ГОТОВО н');

повратак 0;

}

Састављање и покретање тестова 1 и 2

Да бисте направили ове примере, биће вам потребни развојни алати инсталирани на вашој дистрибуцији. На Дебиан -у и Убунту -у ово можете инсталирати помоћу:

погоданинсталирајбуилд-ессентиалс

Затим компајлирајте са:

гццтест1.ц-илитест1&& гццтест2.ц-илитест2

Да бисте покренули оба и тестирали перформансе, покрените:

време./тест1&& време./тест2

Требали бисте добити овакве резултате:

И/О тест са традиционалним глибц функцијама.

Додељивање 64 МБ бафера: ГОТОВО
Записивање података у први бафер: ГОТОВО
Копирање података из прве датотеке у другу: ГОТОВО
Ослобађање бафера: ГОТОВО
Брисање датотека: ГОТОВО
реал 0м0.397с
корисник 0м0.000с
сис 0м0.203с
И/О тест са сендфиле () и повезани системски позиви.
Додељивање 64 МБ бафера: ГОТОВО
Записивање података у први бафер: ГОТОВО
Копирање података из прве датотеке у другу: ГОТОВО
Ослобађање бафера: ГОТОВО
Брисање датотека: ГОТОВО
реал 0м0.019с
корисник 0м0.000с
сис 0м0.016с

Као што видите, код који користи системске позиве ради много брже од еквивалента глибц.

Ствари које треба запамтити

Системски позиви могу повећати перформансе и пружити додатну функционалност, али нису без недостатака. Мораћете да одмерите предности које системски позиви пружају у односу на недостатак преносивости платформе и понекад смањену функционалност у поређењу са функцијама библиотеке.

Када користите неке системске позиве, морате пазити да користите ресурсе враћене из системских позива, а не функције библиотеке. На пример, структура ФИЛЕ која се користи за функције глибц фопен (), фреад (), фврите () и фцлосе () није исто што и број дескриптора датотеке из системског позива опен () (враћен као цео број). Мешањем ових може доћи до проблема.

Генерално, системски позиви Линукса имају мање заштитних трака од функција глибц. Иако је истина да системски позиви имају неке грешке у извештавању и извештавању, добићете детаљније функције помоћу функције глибц.

И на крају, неколико речи о безбедности. Системски позиви се директно повезују са језгром. Језгро Линука заиста има опсежну заштиту од злоупотреба са корисничке земље, али постоје неоткривене грешке. Не верујте да ће системски позив потврдити ваш унос или вас изоловати од безбедносних проблема. Мудро је осигурати да су подаци које предате системском позиву дезинфиковани. Наравно, ово је добар савет за било који АПИ позив, али не можете бити опрезни при раду са језгром.

Надам се да сте уживали у овом дубљем зарону у земљу Линук системских позива. За потпуну листу Линук системских позива погледајте нашу главну листу.