Как стать автором
Обновить
150.19
Beget
Beget — международный облачный провайдер

Системные вызовы Linux, которые должен знать каждый разработчик

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров2.9K

Многие разработчики работают в Linux-среде, но не всегда глубоко понимают, как взаимодействие с ОС происходит на низком уровне. На собеседованиях всё чаще спрашивают про системные вызовы Linux. В этой статье мы рассмотрим, какие вызовы встречаются чаще всего и как они работают.

Эту статью следует рассматривать как Роадмэп и изучать системные вызовы отдельно в других источниках.

Содержание

  1. Почему системные вызовы важны

  2. Работа с файлами и директориями

  3. Процессы и потоки

  4. Межпроцессное взаимодействие (IPC)

  5. Мониторинг и событийная модель

  6. Контейнеризация: namespaces и cgroups

  7. Работа с памятью

  8. Работа с правами и пользователями

  9. Сигналы и управление процессами

  10. Мультиплексирование ввода-вывода

  11. Работа со временем

  12. Выделение и управление памятью через libc

  13. Работа с виртуальной файловой системой

  14. Вопросы на собеседованиях и примеры ответов

  15. Книги

  16. Заключение

Почему системные вызовы важны

Системные вызовы (syscalls) — это интерфейс между пользовательским пространством и ядром ОС. Через них Python (и любая другая программа) запрашивает доступ к ресурсам: файлам, процессам, памяти, сети и др. Даже простой open('file.txt') в Python в итоге приводит к системному вызову open() ядра.

Эти знания важны как на практике, так и для прохождения собеседований.

Многие начинающие разработчики считают, что это все только для senior-разработчиков, но на самом деле теоретическая база не привязана к какому-то грейду. Иначе после ВУЗов мы бы сразу получали senior-разработчиков.

Работа с файлами и директориями

  • open() — открывает файл, возвращает файловый дескриптор.

  • read(), write() — чтение и запись данных по файловому дескриптору.

  • close() — закрывает файловый дескриптор.

  • lseek() — смещение позиции чтения/записи.

  • stat(), fstat() — получение метаданных файла.

  • unlink() — удаление файла (аналог rm).

  • mkdir(), rmdir(), rename() — управление директориями.

  • ftruncate(), truncate() — усечение или расширение файла. Часто ftruncate()используется вместе с mmap() как база для zero-copy append и реализаций кольцевых буферов (ring-buffer).

  • fsync(), fdatasync() — принудительная запись буфера на диск.

  • sync() — сбрасывает все данные файловой системы на диск.

  • fadvise() — даёт ядру подсказки по поводу ожидаемого паттерна доступа к файлу.

  • fallocate() — предварительное выделение места для файла.

  • fcntl() — управление параметрами файловых дескрипторов.

Процессы и потоки

  • fork() — создаёт копию текущего процесса.

  • execve() — заменяет текущий процесс новым.

  • wait(), waitpid() — ожидание завершения дочернего процесса.

  • _exit() — завершение процесса.

  • clone() — низкоуровневый вызов, используемый для создания потоков.

  • getpid(), getppid() — получение PID текущего и родительского процесса.

  • gettid() — получение Thread ID (важно для отладки многопоточности).

  • prctl() — управление поведением процесса (установка имени, запрет core dump и др.).

  • tgkill() — отправка сигнала конкретному потоку.

  • prlimit() — установка ограничений на ресурсы процесса.

Межпроцессное взаимодействие (IPC)

  • pipe() — создание канала связи между процессами.

  • dup(), dup2() — дублирование файловых дескрипторов.

  • socket(), bind(), listen(), accept(), connect() — работа с сетевыми соединениями.

  • send(), recv() — передача данных по сокетам.

  • sendmsg(), recvmsg() — передача структурированных сообщений.

  • shutdown() — корректное завершение соединения.

  • mmap() — отображение файла или памяти в адресное пространство.

  • eventfd(), signalfd(), timerfd() — файловые дескрипторы для событий, сигналов и таймеров.

Мониторинг и событийная модель

  • inotify_init() – инициализирует механизм inotify и возвращает файловый дескриптор.

  • inotify_add_watch(fd, path, mask) – добавляет наблюдение за path с определёнными событиями (mask, например, IN_MODIFY, IN_CREATE и т.д.).

Контейнеризация: namespaces и cgroups

  • unshare() — отделяет текущий процесс в новый namespace (UTS, IPC, mount, user, PID, network и др.).

  • setns() — присоединяет процесс к существующему namespace.

  • clone() с флагами CLONE_NEW* — создание процесса в новых namespaces.

  • mount() и umount2() — монтирование и размонтирование файловых систем (часто в mount namespace).

  • pivot_root() — замена корня корневой ФС контейнера.

  • chroot() — упрощённая версия pivot_root().

  • cgcreate, cgroupfs, cgroup_add_task() (через файловую систему /sys/fs/cgroup) — управление ресурсами через cgroups (ограничение CPU, памяти, IO). cgroups управляются через файловую систему /sys/fs/cgroup, но под капотом используют такие вызовы, как mount, open, write, prlimit и clone.

Работа с памятью

  • mmap(), munmap() — отображение памяти.

  • brk(), sbrk() — управление размером кучи. Используются внутренне в malloc().

Работа с правами и пользователями

  • getuid(), geteuid(), getgid() — идентификаторы пользователя/группы.

  • setuid(), setgid() — смена пользователя/группы.

  • chmod(), chown() — управление правами.

  • umask() — установка маски создания файлов.

  • setrlimit() — установка лимитов ресурсов (CPU, память и т.п.).

  • capget(), capset() — работа с capability-моделью (настройка ограниченных привилегий).

Сигналы и управление процессами

  • kill() — отправка сигнала процессу.

  • tgkill() — отправка сигнала конкретному потоку (используется в многопоточном коде).

  • signal(), sigaction() — установка обработчиков сигналов.

  • signalfd() — получение сигналов как событий через файловый дескриптор.

Мультиплексирование ввода-вывода

  • select() — проверка доступности I/O.

  • poll(), epoll_wait() — более масштабируемые аналоги select.

  • epoll_create1(), epoll_ctl() — управление epoll.

  • splice() — zero-copy перемещение данных между файловыми дескрипторами.

  • io_uring — современный интерфейс асинхронного I/O, предоставляющий высокую производительность и низкие накладные расходы. Используется, например, в современных файловых системах и сетевых стеках.

Работа со временем

  • clock_gettime() — точное получение системного времени.

  • nanosleep() — приостановка на заданное время.

  • gettimeofday() — получение времени в микросекундах (устаревающий, но встречается).

  • timerfd_create() — создание файлового дескриптора с таймером (удобно в event loop).

Выделение и управление памятью через libc

Хотя функции malloc(), calloc(), realloc() и free() не являются системными вызовами напрямую, они работают поверх них. Эти функции — часть стандартной библиотеки libc, которая под капотом использует brk() и mmap() для выделения и освобождения памяти.

  • malloc(size) — выделяет блок памяти заданного размера.

  • calloc(n, size) — выделяет и обнуляет память под массив.

  • realloc(ptr, new_size) — изменяет размер ранее выделенного блока.

  • free(ptr) — освобождает память.

На больших объёмах malloc() может использовать mmap() напрямую, а не brk() — это зависит от аллокатора (ptmalloc, jemalloc, tcmalloc). Это важно знать, особенно при анализе утечек памяти или тюнинге производительности.

Дополнительно:

  • mlock() — защита страниц от выгрузки в swap.

  • mprotect() — изменение прав доступа.

Работа с виртуальной файловой системой

  • procfs (/proc) — виртуальная файловая система, предоставляющая информацию о процессах и состоянии ядра.

  • Используется для мониторинга, отладки, получения PID, информации о памяти, открытых файлах и т.д.

Вопросы на собеседованиях и примеры ответов

Что делает fork() и чем он отличается от exec()?

fork() создаёт копию текущего процесса, exec() заменяет текущий процесс новым. Обычно применяются вместе для запуска новой программы в дочернем процессе.

Как Python работает с файлами на уровне ОС?

Функции open(), read(), write() и др. используют обёртки над системными вызовами open, read, write, предоставляемые glibc.

Чем отличается select от epoll?

select копирует список дескрипторов каждый раз и ограничен 1024 дескрипторами. epoll — масштабируемый и работает по модели событий. io_uring — ещё более современная альтернатива, позволяющая асинхронно выполнять операции с минимальными накладными расходами.

Что такое mmap и где используется?

mmap() позволяет отображать файлы в память, эффективно работать с большими данными и использовать разделяемую память между процессами.

Что такое brk() и как он используется?

brk() расширяет или уменьшает кучу процесса. Используется внутри malloc() для выделения памяти.

Как работает malloc() под капотом?

Вызывает brk() или mmap() для получения памяти из ядра. Маленькие блоки через brk(), большие — через mmap().

Какой системный вызов используется при работе с сокетами в Python?

socket(), bind(), connect(), accept(), send(), recv() — всё это обёртки над соответствующими системными вызовами.

Что такое mlock() и где это нужно?

mlock() блокирует память в RAM, предотвращая её выгрузку в swap. Важно в криптографии, real-time системах и для защиты чувствительных данных.

Зачем нужен mprotect()?

Для защиты памяти от случайного доступа. Например, можно временно запретить запись в чувствительный буфер.

Что такое /proc и как его использовать?

Это виртуальная файловая система для получения информации о процессе и ядре. Примеры использования: чтение cmdline, status, отображение открытых дескрипторов через /proc/<pid>/fd.

Какие вызовы участвуют в изоляции контейнеров?

clone() с CLONE_NEW*, unshare(), setns(), chroot(), pivot_root() — ключевые для реализации контейнеров.

Книги

Книги по системному программированию и системным вызовам Linux

  1. «Linux API. Исчерпывающее руководство»
    Автор: Майкл Керриск
    Подробное руководство по системным вызовам Linux, включая fork(), exec(), mmap(), clone() и другие. Содержит множество примеров и объяснений. Перевод на русский язык доступен, хотя некоторые читатели отмечают, что оригинал на английском языке может быть более точным.

  2. «Linux Kernel Development»
    Автор: Роберт Лав
    Фокусируется на разработке ядра Linux, включая работу с модулями, анализ производительности и оптимизацию.

  3. «Внутреннее устройство Linux»
    Автор: Кетов Дмитрий Владимирович
    Рассмотрены основные подсистемы ядра и их сущности, механизмы контроля доступа и привилегии, принципы и механизмы контейнеризации.

Книги по контейнеризации

  1. «The Docker Book»
    Автор: Джеймс Тёрна
    Подробное руководство по Docker, включая архитектуру, инструменты и методики использования. Содержит многочисленные примеры кода и инструкции.

  2. «Kubernetes: Up and Running»
    Авторы: Кларенс Драгович, Джозеф Джек, Каито Сакуро
    Посвящена системе оркестрации Kubernetes, одной из ключевых технологий в мире контейнеризации. Книга помогает освоить основные принципы и методы работы с Kubernetes.

Заключение

Понимание системных вызовов — это не просто академическое знание. Это основа эффективного взаимодействия с ОС, особенно при разработке высокопроизводительных систем, работы с файлами, процессами или сетями. Даже в Python, где многое абстрагировано, под капотом работают те же самые вызовы ядра.

Если вы хотите расти как инженер — разберитесь, что именно делает ваш код на уровне ОС.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как вы относитесь к io_uring?
6.25% Использую и кайфую1
25% Пока только читал/смотрел доклады4
68.75% Слышал, но не разбирался11
0% Использовал, но отказался (напиши причину в комментариях)0
Проголосовали 16 пользователей. Воздержались 9 пользователей.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой уровень работы с Linux вы считаете «обязательным минимумом» для разработчика?
75% Понимание, что делает fork(), exec()12
31.25% Умение объяснить, как работает select()5
37.5% Уверенное использование mmap, fcntl, statx6
31.25% Знание clone, cgroups, io_uring, pivot_root5
25% Всё выше перечисленное4
Проголосовали 16 пользователей. Воздержались 7 пользователей.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Что из этого вас спрашивали на собеседованиях?
30.77% fork / exec и процессная модель4
7.69% mmap и zero-copy1
23.08% Сравнение select / poll / epoll3
30.77% Работа с правами (getuid, setuid)4
15.38% namespaces и cgroups2
46.15% Ничего из этого6
Проголосовали 13 пользователей. Воздержались 8 пользователей.
Теги:
Хабы:
+17
Комментарии6

Публикации

Информация

Сайт
beget.com
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия