Pengaturcaraan C

Tutorial Panggilan Sistem Linux dengan C

Tutorial Panggilan Sistem Linux dengan C
Dalam artikel terakhir kami mengenai Panggilan Sistem Linux, saya menentukan panggilan sistem, membincangkan sebab-sebab seseorang menggunakannya dalam program, dan mengetahui kelebihan dan kekurangannya. Saya bahkan memberikan contoh ringkas dalam perhimpunan di C. Ini menggambarkan intinya dan menerangkan cara membuat panggilan, tetapi tidak menghasilkan apa-apa. Bukan betul-betul latihan pembangunan yang mendebarkan, tetapi ini menggambarkan intinya.

Dalam artikel ini, kita akan menggunakan panggilan sistem sebenar untuk melakukan kerja sebenar dalam program C kita. Pertama, kami akan menyemak jika anda perlu menggunakan panggilan sistem, kemudian memberikan contoh menggunakan panggilan sendfile () yang dapat meningkatkan prestasi salinan fail secara dramatik. Akhirnya, kami akan membahas beberapa perkara yang perlu diingat semasa menggunakan panggilan sistem Linux.

Adakah Anda Memerlukan Panggilan Sistem?

Walaupun tidak dapat dielakkan anda akan menggunakan panggilan sistem pada suatu ketika dalam karier pengembangan C anda, melainkan jika anda menyasarkan prestasi tinggi atau fungsi jenis tertentu, perpustakaan glibc dan perpustakaan asas lain yang termasuk dalam pengedaran Linux utama akan mengurus sebahagian besar keperluan anda.

Perpustakaan standard glibc menyediakan kerangka rentas platform yang diuji dengan baik untuk melaksanakan fungsi yang sebaliknya memerlukan panggilan sistem khusus sistem. Contohnya, anda boleh membaca fail dengan fscanf (), fread (), getc (), dll., atau anda boleh menggunakan panggilan sistem baca () Linux. Fungsi glibc memberikan lebih banyak ciri (i.e. pengendalian ralat yang lebih baik, IO yang diformat, dll.) dan akan berfungsi pada mana-mana sistem sokongan glibc.

Sebaliknya, ada kalanya prestasi tanpa kompromi dan pelaksanaan yang tepat sangat penting. Pembungkus yang disediakan oleh fread () akan menambah overhead, dan walaupun kecil, tidak sepenuhnya telus. Selain itu, anda mungkin tidak mahu atau memerlukan ciri tambahan yang disediakan pembungkus. Sekiranya demikian, anda paling senang dilayan dengan panggilan sistem.

Anda juga boleh menggunakan panggilan sistem untuk melakukan fungsi yang belum disokong oleh glibc. Sekiranya salinan glibc anda terkini, ini tidak akan menjadi masalah, tetapi pengembangan pada pengedaran yang lebih lama dengan kernel yang lebih baru mungkin memerlukan teknik ini.

Setelah anda membaca penafian, amaran, dan kemungkinan jalan memutar, sekarang mari kita menggali beberapa contoh praktikal.

CPU Apa Yang Kita Hidup?

Soalan yang mungkin tidak difikirkan oleh kebanyakan program, tetapi tetap sah. Ini adalah contoh panggilan sistem yang tidak dapat digandakan dengan glibc dan tidak ditutup dengan pembungkus glibc. Dalam kod ini, kita akan memanggil panggilan getcpu () secara langsung melalui fungsi syscall (). Fungsi syscall berfungsi seperti berikut:

syscall (SYS_call, arg1, arg2,…);

Argumen pertama, SYS_call, adalah definisi yang mewakili bilangan panggilan sistem. Apabila anda memasukkan sys / syscall.h, ini disertakan. Bahagian pertama adalah SYS_ dan bahagian kedua adalah nama panggilan sistem.

Hujah untuk panggilan masuk ke arg1, arg2 di atas. Sebilangan panggilan memerlukan lebih banyak hujah, dan ia akan disambung mengikut urutan dari halaman manual mereka. Ingatlah bahawa kebanyakan argumen, terutama untuk pengembalian, memerlukan penunjuk untuk menyusun array atau memori yang diperuntukkan melalui fungsi malloc.

contoh1.c

#sertakan
#sertakan
#sertakan
#sertakan
 
int utama ()
 
cpu yang tidak ditandatangani, nod;
 
// Dapatkan inti CPU dan nod NUMA semasa melalui panggilan sistem
// Perhatikan ini tidak mempunyai pembungkus glibc jadi kita mesti memanggilnya secara langsung
syscall (SYS_getcpu, & cpu, & node, NULL);
 
// Paparkan maklumat
printf ("Program ini dijalankan pada CPU core% u dan NUMA node% u.\ n \ n ", cpu, nod);
 
pulangan 0;
 

 
Untuk menyusun dan menjalankan:
 
contoh gcc1.c -o contoh1
./ contoh1

Untuk hasil yang lebih menarik, anda boleh memutar utas melalui pustaka pthreads dan kemudian memanggil fungsi ini untuk melihat pemproses yang dijalankan oleh utas anda.

Sendfile: Prestasi Unggul

Sendfile memberikan contoh terbaik untuk meningkatkan prestasi melalui panggilan sistem. Fungsi sendfile () menyalin data dari satu deskriptor fail ke yang lain. Daripada menggunakan beberapa fungsi fread () dan fwrite (), sendfile melakukan pemindahan di ruang kernel, mengurangkan overhead dan dengan itu meningkatkan prestasi.

Dalam contoh ini, kita akan menyalin 64 MB data dari satu fail ke fail lain. Dalam satu ujian, kami akan menggunakan kaedah membaca / menulis standard di pustaka standard. Yang lain, kami akan menggunakan panggilan sistem dan panggilan sendfile () untuk meletupkan data ini dari satu lokasi ke lokasi lain.

ujian1.c (glibc)

#sertakan
#sertakan
#sertakan
#sertakan
 
#tentukan BUFFER_SIZE 67108864
#tentukan BUFFER_1 "penyangga1"
#tentukan BUFFER_2 "penyangga2"
 
int utama ()
 
FILE * fOut, * fIn;
 
printf ("\ nI / O uji dengan fungsi glibc tradisional.\ n \ n ");
 
// Rebut buffer BUFFER_SIZE.
// Penyangga akan mempunyai data rawak di dalamnya tetapi kami tidak mempedulikannya.
printf ("Memperuntukkan penyangga 64 MB:");
char * buffer = (char *) malloc (BUFFER_SIZE);
printf ("SELESAI \ n");
 
// Tulis penyangga ke fOut
printf ("Menulis data ke penyangga pertama:");
fOut = fopen (BUFFER_1, "wb");
fwrite (penyangga, sizeof (char), BUFFER_SIZE, fOut);
fclose (fOut);
printf ("SELESAI \ n");
 
printf ("Menyalin data dari fail pertama ke kedua:");
fIn = fopen (BUFFER_1, "rb");
fOut = fopen (BUFFER_2, "wb");
fread (penyangga, sizeof (char), BUFFER_SIZE, fIn);
fwrite (penyangga, sizeof (char), BUFFER_SIZE, fOut);
fclose (fIn);
fclose (fOut);
printf ("SELESAI \ n");
 
printf ("Membebaskan penampan:");
percuma (penyangga);
printf ("SELESAI \ n");
 
printf ("Menghapus fail:");
alih keluar (BUFFER_1);
alih keluar (BUFFER_2);
printf ("SELESAI \ n");
 
pulangan 0;
 

ujian2.c (panggilan sistem)

#sertakan
#sertakan
#sertakan
#sertakan
#sertakan
#sertakan
#sertakan
#sertakan
#sertakan
 
#tentukan BUFFER_SIZE 67108864
 
int utama ()
 
int fOut, fIn;
 
printf ("\ nI / O test dengan sendfile () dan panggilan sistem yang berkaitan.\ n \ n ");
 
// Raih buffer BUFFER_SIZE.
// Penyangga akan mempunyai data rawak di dalamnya tetapi kami tidak mempedulikannya.
printf ("Memperuntukkan penyangga 64 MB:");
char * buffer = (char *) malloc (BUFFER_SIZE);
printf ("SELESAI \ n");
 
// Tulis penyangga ke fOut
printf ("Menulis data ke penyangga pertama:");
fOut = terbuka ("buffer1", O_RDONLY);
tulis (fOut, & buffer, BUFFER_SIZE);
tutup (fOut);
printf ("SELESAI \ n");
 
printf ("Menyalin data dari fail pertama ke kedua:");
fIn = terbuka ("buffer1", O_RDONLY);
fOut = terbuka ("buffer2", O_RDONLY);
sendfile (fOut, fIn, 0, BUFFER_SIZE);
tutup (fIn);
tutup (fOut);
printf ("SELESAI \ n");
 
printf ("Membebaskan penampan:");
percuma (penyangga);
printf ("SELESAI \ n");
 
printf ("Menghapus fail:");
nyahpaut ("buffer1");
nyahpaut ("buffer2");
printf ("SELESAI \ n");
 
pulangan 0;
 

Menyusun dan Menjalankan Ujian 1 & 2

Untuk membina contoh-contoh ini, anda memerlukan alat pengembangan yang dipasang pada pengedaran anda. Di Debian dan Ubuntu, anda boleh memasangnya dengan:

pasang membina keperluan-keperluan

Kemudian kompilasi dengan:

ujian gcc1.c -o test1 && gcc test2.ujian c -o2

Untuk menjalankan kedua-duanya dan menguji prestasinya, jalankan:

masa ./ ujian1 && masa ./ ujian2

Anda akan mendapat hasil seperti ini:

Uji I / O dengan fungsi glibc tradisional.

Memperuntukkan penimbal 64 MB: SELESAI
Menulis data ke penyangga pertama: SELESAI
Menyalin data dari fail pertama ke kedua: SELESAI
Membebaskan penyangga: SELESAI
Memadam fail: SELESAI
sebenar 0m0.397an
pengguna 0m0.000s
sys 0m0.203-an
Uji I / O dengan sendfile () dan panggilan sistem yang berkaitan.
Memperuntukkan penimbal 64 MB: SELESAI
Menulis data ke penyangga pertama: SELESAI
Menyalin data dari fail pertama ke kedua: SELESAI
Membebaskan penyangga: SELESAI
Memadam fail: SELESAI
sebenar 0m0.019an
pengguna 0m0.000s
sys 0m0.016s

Seperti yang anda lihat, kod yang menggunakan panggilan sistem berjalan lebih pantas daripada setara glibc.

Perkara yang Perlu Diingat

Panggilan sistem dapat meningkatkan prestasi dan memberikan fungsi tambahan, tetapi bukan tanpa kekurangannya. Anda harus mempertimbangkan faedah yang diberikan oleh sistem panggilan daripada kekurangan portabiliti platform dan kadangkala fungsi yang dikurangkan berbanding fungsi perpustakaan.

Semasa menggunakan beberapa panggilan sistem, anda mesti berhati-hati menggunakan sumber yang dikembalikan dari panggilan sistem dan bukannya fungsi perpustakaan. Sebagai contoh, struktur FILE yang digunakan untuk fungsi fiben (), fread (), fwrite (), dan fclose () glibc tidak sama dengan nombor deskriptor fail dari panggilan sistem terbuka () (dikembalikan sebagai bilangan bulat). Mencampurkan ini boleh menimbulkan masalah.

Secara umum, panggilan sistem Linux mempunyai jalur bumper yang lebih sedikit daripada fungsi glibc. Walaupun benar bahawa panggilan sistem mempunyai beberapa pengendalian dan pelaporan ralat, anda akan mendapat fungsi yang lebih terperinci dari fungsi glibc.

Dan akhirnya, kata keselamatan. Panggilan sistem secara langsung bersambung dengan kernel. Kernel Linux memang mempunyai perlindungan yang luas terhadap shenanigans dari tanah pengguna, tetapi ada bug yang belum ditemui. Jangan percaya bahawa panggilan sistem akan mengesahkan input anda atau mengasingkan anda dari masalah keselamatan. Adalah bijak untuk memastikan data yang anda berikan kepada panggilan sistem dibersihkan. Secara semula jadi, ini adalah nasihat yang baik untuk sebarang panggilan API, tetapi anda tidak boleh berhati-hati ketika bekerja dengan kernel.

Saya harap anda menikmati selaman yang lebih mendalam ini ke dalam panggilan sistem Linux. Untuk senarai lengkap Panggilan Sistem Linux, lihat senarai induk kami.

Cara Membangunkan Permainan di Linux
Satu dekad yang lalu, tidak banyak pengguna Linux akan meramalkan bahawa sistem operasi kegemaran mereka suatu hari nanti akan menjadi platform permai...
Port Sumber Terbuka Mesin Permainan Komersial
Rekreasi enjin permainan sumber terbuka dan bebas platform boleh digunakan untuk bermain lama dan juga beberapa tajuk permainan yang baru-baru ini. Ar...
Permainan Perintah Terbaik untuk Linux
Baris perintah bukan hanya sekutu terbesar anda ketika menggunakan Linux-ia juga dapat menjadi sumber hiburan kerana anda dapat menggunakannya untuk m...