Pemrograman C

Tutorial Panggilan Sistem Linux dengan C

Tutorial Panggilan Sistem Linux dengan C
Dalam artikel terakhir kami tentang Panggilan Sistem Linux, saya mendefinisikan panggilan sistem, membahas alasan seseorang menggunakannya dalam suatu program, dan mempelajari kelebihan dan kekurangannya. Saya bahkan memberikan contoh singkat dalam perakitan dalam C. Itu mengilustrasikan intinya dan menjelaskan cara melakukan panggilan, tetapi tidak menghasilkan apa-apa. Bukan latihan pengembangan yang mendebarkan, tetapi itu menggambarkan intinya.

Pada artikel ini, kita akan menggunakan panggilan sistem yang sebenarnya untuk melakukan pekerjaan nyata dalam program C kita. Pertama, kami akan meninjau jika Anda perlu menggunakan panggilan sistem, kemudian memberikan contoh menggunakan panggilan sendfile() yang dapat secara dramatis meningkatkan kinerja penyalinan file. Akhirnya, kita akan membahas beberapa hal yang perlu diingat saat menggunakan panggilan sistem Linux.

Apakah Anda Membutuhkan Panggilan Sistem??

Meskipun tidak dapat dihindari, Anda akan menggunakan panggilan sistem di beberapa titik dalam karir pengembangan C Anda, kecuali jika Anda menargetkan kinerja tinggi atau fungsionalitas tipe tertentu, pustaka glibc dan pustaka dasar lainnya yang termasuk dalam distribusi Linux utama akan menangani sebagian besar kebutuhanmu.

Pustaka standar glibc menyediakan kerangka kerja lintas platform yang telah teruji dengan baik untuk menjalankan fungsi yang memerlukan panggilan sistem khusus sistem. Misalnya, Anda dapat membaca file dengan fscanf(), fread(), getc(), dll., atau Anda dapat menggunakan read() panggilan sistem Linux. Fungsi glibc menyediakan lebih banyak fitur (mis.e. penanganan kesalahan yang lebih baik, IO yang diformat, dll.) dan akan bekerja pada sistem apa pun yang didukung glibc.

Di sisi lain, ada saat-saat di mana kinerja tanpa kompromi dan eksekusi yang tepat sangat penting. Pembungkus yang disediakan fread() akan menambah overhead, dan meskipun kecil, tidak sepenuhnya transparan. Selain itu, Anda mungkin tidak menginginkan atau membutuhkan fitur tambahan yang disediakan pembungkusnya. Dalam hal ini, Anda sebaiknya dilayani dengan panggilan sistem system.

Anda juga dapat menggunakan panggilan sistem untuk melakukan fungsi yang belum didukung oleh glibc. Jika salinan glibc Anda mutakhir, ini tidak akan menjadi masalah, tetapi mengembangkan distro lama dengan kernel yang lebih baru mungkin memerlukan teknik ini.

Sekarang setelah Anda membaca penafian, peringatan, dan kemungkinan jalan memutar, sekarang mari kita gali beberapa contoh praktis.

CPU apa yang kita pakai?

Sebuah pertanyaan yang mungkin tidak terpikirkan oleh sebagian besar program, tetapi tetap valid. Ini adalah contoh panggilan sistem yang tidak dapat diduplikasi dengan glibc dan tidak ditutupi dengan pembungkus glibc. Dalam kode ini, kita akan memanggil panggilan getcpu() secara langsung melalui fungsi syscall(). Fungsi syscall bekerja sebagai berikut:

syscall(SYS_call, arg1, arg2,… ​​);

Argumen pertama, SYS_call, adalah definisi yang mewakili nomor panggilan sistem. Saat Anda memasukkan sys/syscall.h, ini termasuk. Bagian pertama adalah SYS_ dan bagian kedua adalah nama panggilan sistem.

Argumen untuk panggilan masuk ke arg1, arg2 di atas. Beberapa panggilan memerlukan lebih banyak argumen, dan mereka akan melanjutkan secara berurutan dari halaman manual mereka. Ingat bahwa sebagian besar argumen, terutama untuk pengembalian, akan memerlukan pointer ke array char atau memori yang dialokasikan melalui fungsi malloc.

Contoh 1.c

#termasuk
#termasuk
#termasuk
#termasuk
 
int utama()
 
cpu yang tidak ditandatangani, simpul;
 
// Dapatkan inti CPU dan simpul NUMA saat ini melalui panggilan sistem
// Perhatikan ini tidak memiliki pembungkus glibc jadi kita harus memanggilnya secara langsung
syscall(SYS_getcpu, &cpu, &node, NULL);
 
// Menampilkan informasi
printf("Program ini berjalan pada inti CPU %u dan NUMA node %u.\n\n", cpu, simpul);
 
kembali 0;
 

 
Untuk mengkompilasi dan menjalankan:
 
contoh gcc1.c -o contoh1
./Contoh 1

Untuk hasil yang lebih menarik, Anda dapat memutar utas melalui pustaka pthreads dan kemudian memanggil fungsi ini untuk melihat prosesor mana yang menjalankan utas Anda.

Sendfile: Performa Unggul

Sendfile memberikan contoh yang sangat baik untuk meningkatkan kinerja melalui panggilan sistem. Fungsi sendfile() menyalin data dari satu deskriptor file ke yang lain. Daripada menggunakan beberapa fungsi fread() dan fwrite(), sendfile melakukan transfer di ruang kernel, mengurangi overhead dan dengan demikian meningkatkan kinerja.

Dalam contoh ini, kita akan menyalin 64 MB data dari satu file ke file lainnya. Dalam satu pengujian, kita akan menggunakan metode baca/tulis standar di perpustakaan standar. Di sisi lain, kami akan menggunakan panggilan sistem dan panggilan sendfile() untuk meledakkan data ini dari satu lokasi ke lokasi lain.

tes1.c (glibc)

#termasuk
#termasuk
#termasuk
#termasuk
 
#tentukan BUFFER_SIZE 67108864
#define BUFFER_1 "buffer1"
#define BUFFER_2 "buffer2"
 
int utama()
 
FILE *fOut, *fIn;
 
printf("\nUji I/O dengan fungsi glibc tradisional.\n\n");
 
// Ambil buffer BUFFER_SIZE.
// Buffer akan memiliki data acak di dalamnya tapi kami tidak peduli tentang itu.
printf("Mengalokasikan 64 MB buffer:                   ");
char *buffer = (char *) malloc(BUFFER_SIZE);
printf("SELESAI\n");
 
// Tulis buffer ke fOut
printf("Menulis data ke buffer pertama:              ");
fOut = fopen(BUFFER_1, "wb");
fwrite(buffer, sizeof(char), BUFFER_SIZE, fOut);
ftutup(fKeluar);
printf("SELESAI\n");
 
printf("Menyalin data dari file pertama ke file kedua:      ");
fIn = fopen(BUFFER_1, "rb");
fOut = fopen(BUFFER_2, "wb");
fread(buffer, sizeof(char), BUFFER_SIZE, fIn);
fwrite(buffer, sizeof(char), BUFFER_SIZE, fOut);
ftutup(fIn);
ftutup(fKeluar);
printf("SELESAI\n");
 
printf("Membebaskan buffer:                           ");
gratis (penyangga);
printf("SELESAI\n");
 
printf("Menghapus file:                           ");
hapus(BUFFER_1);
hapus(BUFFER_2);
printf("SELESAI\n");
 
kembali 0;
 

tes2.c (panggilan sistem)

#termasuk
#termasuk
#termasuk
#termasuk
#termasuk
#termasuk
#termasuk
#termasuk
#termasuk
 
#tentukan BUFFER_SIZE 67108864
 
int utama()
 
int fOut, fIn;
 
printf("\nI/O tes dengan sendfile() dan panggilan sistem terkait.\n\n");
 
// Ambil buffer BUFFER_SIZE.
// Buffer akan memiliki data acak di dalamnya tapi kami tidak peduli tentang itu.
printf("Mengalokasikan 64 MB buffer:                   ");
char *buffer = (char *) malloc(BUFFER_SIZE);
printf("SELESAI\n");
 
// Tulis buffer ke fOut
printf("Menulis data ke buffer pertama:              ");
fOut = open("buffer1", O_RDONLY);
write(fOut, &buffer, BUFFER_SIZE);
tutup(fKeluar);
printf("SELESAI\n");
 
printf("Menyalin data dari file pertama ke file kedua:      ");
fIn = buka("buffer1", O_RDONLY);
fOut = open("buffer2", O_RDONLY);
sendfile(fOut, fIn, 0, BUFFER_SIZE);
tutup(fIn);
tutup(fKeluar);
printf("SELESAI\n");
 
printf("Membebaskan buffer:                           ");
gratis (penyangga);
printf("SELESAI\n");
 
printf("Menghapus file:                           ");
batalkan tautan("penyangga1");
batalkan tautan("penyangga2");
printf("SELESAI\n");
 
kembali 0;
 

Mengkompilasi dan Menjalankan Tes 1 & 2

Untuk membuat contoh-contoh ini, Anda memerlukan alat pengembangan yang diinstal pada distribusi Anda. Di Debian dan Ubuntu, Anda dapat menginstal ini dengan:

apt install build-essential

Kemudian kompilasi dengan:

tes gcc1.c -o test1 && gcc test2.c -o tes2

Untuk menjalankan keduanya dan menguji kinerja, jalankan:

waktu ./test1 && waktu ./tes2

Anda harus mendapatkan hasil seperti ini:

Tes I/O dengan fungsi glibc tradisional.

Mengalokasikan buffer 64 MB:                   SELESAI
Menulis data ke buffer pertama:              SELESAI
Menyalin data dari file pertama ke file kedua:      SELESAI
Membebaskan buffer:                          SELESAI
Menghapus file:                           SELESAI
nyata    0m0.397 detik
pengguna    0m0.000s
sys     0m0.203 detik
Tes I/O dengan sendfile() dan panggilan sistem terkait.
Mengalokasikan buffer 64 MB:                   SELESAI
Menulis data ke buffer pertama:              SELESAI
Menyalin data dari file pertama ke file kedua:      SELESAI
Membebaskan buffer:                          SELESAI
Menghapus file:                          SELESAI
nyata    0m0.019
pengguna    0m0.000s
sys     0m0.016s

Seperti yang Anda lihat, kode yang menggunakan panggilan sistem berjalan jauh lebih cepat daripada yang setara dengan glibc.

Hal-hal untuk diingat

Panggilan sistem dapat meningkatkan kinerja dan menyediakan fungsionalitas tambahan, tetapi bukan tanpa kekurangannya. Anda harus mempertimbangkan manfaat yang diberikan panggilan sistem terhadap kurangnya portabilitas platform dan terkadang fungsionalitas yang berkurang dibandingkan dengan fungsi perpustakaan library.

Saat menggunakan beberapa panggilan sistem, Anda harus berhati-hati untuk menggunakan sumber daya yang dikembalikan dari panggilan sistem daripada fungsi perpustakaan. Misalnya, struktur FILE yang digunakan untuk fungsi fopen(), fread(), fwrite(), dan fclose() glibc tidak sama dengan nomor deskriptor file dari panggilan sistem open() (dikembalikan sebagai bilangan bulat). Mencampur ini dapat menyebabkan masalah.

Secara umum, panggilan sistem Linux memiliki lebih sedikit jalur bumper daripada fungsi glibc. Meskipun benar bahwa panggilan sistem memiliki beberapa penanganan dan pelaporan kesalahan, Anda akan mendapatkan fungsionalitas yang lebih mendetail dari fungsi glibc.

Dan akhirnya, sepatah kata tentang keamanan. Panggilan sistem langsung berinteraksi dengan kernel. Kernel Linux memang memiliki perlindungan ekstensif terhadap kejahatan dari tanah pengguna, tetapi ada bug yang belum ditemukan. Jangan percaya bahwa panggilan sistem akan memvalidasi input Anda atau mengisolasi Anda dari masalah keamanan. Adalah bijaksana untuk memastikan data yang Anda berikan ke panggilan sistem telah disanitasi. Tentu saja, ini adalah saran yang bagus untuk panggilan API apa pun, tetapi Anda tidak dapat berhati-hati saat bekerja dengan kernel.

Saya harap Anda menikmati penyelaman lebih dalam ke tanah panggilan sistem Linux ini. Untuk daftar lengkap Panggilan Sistem Linux, lihat daftar utama kami.

Tambahkan gerakan Mouse ke Windows 10 menggunakan alat gratis ini
Dalam beberapa tahun terakhir, komputer dan sistem operasi telah berkembang pesat. Ada saat ketika pengguna harus menggunakan perintah untuk menavigas...
Kontrol & kelola gerakan mouse di antara beberapa monitor di Windows 10
Manajer Mouse Tampilan Ganda memungkinkan Anda mengontrol & mengonfigurasi gerakan mouse di antara beberapa monitor, dengan memperlambat gerakannya di...
WinMouse memungkinkan Anda menyesuaikan & meningkatkan gerakan penunjuk tetikus di PC Windows
Jika Anda ingin meningkatkan fungsi default penunjuk tetikus Anda, gunakan freeware WinMouse. Ini menambahkan lebih banyak fitur untuk membantu Anda m...