システムコール

May 03, 2018

はじめに

せっかくゴールデンウィークに入ったので、1 年間で学んできたことを復習する意味でも、最近更新が滞っているこのブログに残しておこうと思いました。
基本的には Linux 周りのことを書くと思います。アドカレみたいなのりです。

システムコール

システムコールというのは、各種プロセスが、別のプロセスを生成したり、ハードウェアを操作したりする際に、カーネル側に処理を依頼する方法となる。
具体的には以下のような操作を実施する場合にはシステムコール経由で行う必要がある。

  • プロセス生成/削除
  • メモリ確保/解放
  • プロセス間通信
  • ネットワーク周辺操作
  • ファイルシステム操作
  • ファイル操作 (デバイスアクセス)

システムコールが発布される際は CPU がユーザーモードからカーネルモード (Ring 3 -> Ring 0) に遷移し、要求の正当性を判断した上で、システムコールを受諾する。

実験

Hello World

まずは、簡単な Hello World コードを書き、strace で結果を見てみる。

#include <stdio.h>  
  
int main(void) {  
  puts("Hello World!");  
  return 0;  
}  
$ gcc -o hello hello.c   
$ strace -o hello.log ./hello  
Hello World!  
  
$ cat hello.log   
execve("./hello", ["./hello"], [/* 33 vars */]) = 0  
brk(0)                                  = 0x2360000  
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9313b2b000  
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)  
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3  
fstat(3, {st_mode=S_IFREG|0644, st_size=20510, ...}) = 0  
mmap(NULL, 20510, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9313b25000  
close(3)                                = 0  
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3  
read(3, "\177ELF\2\1\1\3&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;\3&#92;&#48;>&#92;&#48;\1&#92;&#48;&#92;&#48;&#92;&#48;\20\35\2&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;"..., 832) = 832  
fstat(3, {st_mode=S_IFREG|0755, st_size=2122040, ...}) = 0  
mmap(NULL, 3944896, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f9313547000  
mprotect(0x7f9313701000, 2093056, PROT_NONE) = 0  
mmap(0x7f9313900000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b9000) = 0x7f9313900000  
mmap(0x7f9313906000, 16832, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f9313906000  
close(3)                                = 0  
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9313b24000  
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9313b22000  
arch_prctl(ARCH_SET_FS, 0x7f9313b22740) = 0  
mprotect(0x7f9313900000, 16384, PROT_READ) = 0  
mprotect(0x7f9313b2c000, 4096, PROT_READ) = 0  
munmap(0x7f9313b25000, 20510)           = 0  
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0  
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9313b2a000  
write(1, "Hello World!\n", 13)          = 13  
exit_group(0)                           = ?  
+++ exited with 0 +++  

色々システムコールが呼ばれているが、重要なのは write() システムコールがちゃんと呼ばれているところ。
他にも mmap() でメモリを確保したり、一番最初に execve() で bash から fork したこのプロセスを exec したりしてる。

システムコールなし

システムコールを発行しないような、ただただ無限にループするプロセスを作成する。

#include <stdio.h>  
  
int main(void) {  
  for(;;)  
    ;  
}  
$ gcc -o loop loop.c  
$ ./loop &amp;  
[1] 3384  
  
$ sar -P ALL 1 1  
Linux 4.14.26-46.32.amzn1.x86_64 (ip-10-1-11-92) 	05/02/2018 	_x86_64_	(8 CPU)  
  
10:53:56 PM     CPU     %user     %nice   %system   %iowait    %steal     %idle  
10:53:57 PM     all     12.50      0.00      0.12      0.00      0.00     87.38  
10:53:57 PM       0      0.00      0.00      0.00      0.00      0.00    100.00  
10:53:57 PM       1      0.00      0.00      0.00      0.00      0.00    100.00  
10:53:57 PM       2      0.00      0.00      0.00      0.00      0.00    100.00  
10:53:57 PM       3      0.00      0.00      0.00      0.00      0.00    100.00  
10:53:57 PM       4    100.00      0.00      0.00      0.00      0.00      0.00  
10:53:57 PM       5      0.00      0.00      0.00      0.00      0.00    100.00  
10:53:57 PM       6      0.00      0.00      0.00      0.00      0.00    100.00  
10:53:57 PM       7      0.00      0.00      0.00      0.00      0.00    100.00  

CPU4 の user 値だけが 100% になっていることを確認できる。


 © 2023, Dealing with Ambiguity