System call

Żądanie wysyłane przez program z przestrzeni użytkownika do jądra o wykonanie usługi, np. otwarcie pliku czy alokację pamięci. Główny punkt styku aplikacji z jądrem.

System call (wywołanie systemowe) to kontrolowane żądanie, które program z przestrzeni użytkownika (user space) wysyła do jądra systemu (kernel), żeby ono wykonało za niego operację, do której zwykła aplikacja nie ma uprawnień: otworzenie pliku, alokację pamięci, wysłanie pakietu po sieci albo utworzenie nowego procesu. To główny i w praktyce jedyny legalny punkt styku między Twoim kodem a jądrem.

Jak to działa

Procesor pracuje w co najmniej dwóch trybach: user mode i kernel mode. Twój kod w user mode nie może sam grzebać w sprzęcie czy pamięci innych procesów, bo skończyłoby się to chaosem i dziurami w bezpieczeństwie. Kiedy program potrzebuje usługi jądra, wykonuje specjalną instrukcję procesora (na x86-64 Linuksa to syscall), która przełącza CPU w kernel mode i oddaje sterowanie do handlera w jądrze. Numer wywołania ląduje w rejestrze (na x86-64 w rax), argumenty w kolejnych rejestrach, a po wykonaniu jądro wraca do programu z wynikiem.

W praktyce rzadko wołasz syscall ręcznie. Robi to za Ciebie glibc i jego wrappery: funkcja open() z C tak naprawdę przygotowuje argumenty i wykonuje wywołanie openat. Dlatego mówi się, że standardowa biblioteka C to cienka warstwa nad system calls.

Przykład z praktyki

Chcesz zobaczyć, co naprawdę robi program pod spodem? Użyj strace. To narzędzie przechwytuje każde wywołanie systemowe procesu i wypisuje je z argumentami:

  • strace -f ls /tmp — pokaże m.in. openat, read, write, close i mmap.
  • strace -c curl example.com — policzy, ile czasu spędzono w którym syscallu (świetne do szukania wąskich gardeł).

Gdy aplikacja „wisi” bez logów, strace -p PID często od razu pokazuje, że proces stoi na read albo futex i czeka na coś, co nie nadchodzi.

Częste błędy i mity

Mit: system call jest darmowy. Nie jest. Przełączenie kontekstu user↔kernel kosztuje. Dlatego czytanie pliku po jednym bajcie (osobny read za każdym razem) potrafi być setki razy wolniejsze niż jeden większy bufor — buforowanie w bibliotekach C istnieje właśnie po to.

Pułapka: ignorowanie wartości zwracanej. Syscall może zwrócić błąd przez ujemną wartość i ustawić errno (np. EAGAIN, ENOENT). Brak sprawdzenia to klasyk, na którym wykładają się juniorskie programy.

Nie myl pojęć: system call to nie to samo co wywołanie funkcji biblioteki (library call) — to drugie może, ale nie musi, schodzić do jądra.

Pojęcia powiązane

kernel mode i user mode, context switch, glibc, strace i ltrace, ABI, interrupt, ptrace, a także seccomp, który pozwala ograniczać dostępne procesowi wywołania systemowe.