Проектирование IPC в микроядре
- title
- Проектирование IPC в микроядре
- type
- summary
- summary
- Разбор архитектуры IPC в FTL от Seiya Nuta: notify-and-pull, отказ от IDL, операции в духе Plan 9 и схема peek-then-receive
- tags
- microkernel, ipc, operating-systems, message-passing, rust
- sources
- microkernel-ipc-design
- created
- 2026-05-06
- updated
- 2026-07-29
- lang
- ru
- translation_of
- microkernel-ipc-design
- source_updated
- 2026-07-29
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Seiya Nuta - автор Resea и находящейся в разработке операционной системы FTL. Этот пост - рабочий дневник переработки IPC в FTL за несколько недель. Он написан как экскурсия от хрестоматийной отправной точки ("IPC - это memcpy(2) между процессами") до конкретных проектных решений, к которым в итоге пришла FTL. Такая подача удобна тем, что в каждом разделе хрестоматийный подход сопоставляется с конкретным сценарием сбоя, который подтолкнул FTL к другому решению.
Четыре шага аргументации
1. Передача сообщений - основа микроядра. У каждого сообщения есть тип, полезная нагрузка (payload) и набор handle'ов. Драйверы, стек TCP/IP и файловая система - это процессы пользовательского режима, общающиеся через почтовые ящики (mailboxes): ipc_send / ipc_receive, одинаковый API с обоих концов. Чтение файла превращается в RPC: клиент отправляет FILE_READ_MSG, сервер отвечает байтами.
2. Синхронный IPC проще отлаживать, но он приводит к взаимным блокировкам (deadlock) между серверами. Асинхронный IPC означает, что ядро ставит сообщения в очередь. Это требует динамического выделения памяти, создает проблемы с backpressure и открывает вектор для DoS. Hubris и Resea выбрали синхронный подход именно по этой причине. Однако синхронный IPC сам по себе блокируется насмерть, как только два сервиса пытаются отправить данные друг другу: канонический пример - сервер TCP/IP и драйвер Ethernet, где каждый отправляет до того, как другой перейдет в состояние приёма. Для обхода этой проблемы Nuta вводит термин notify-and-pull: сервер отправляет неблокирующее уведомление (флаг в почтовом ящике, без данных и без счётчика), а клиент реагирует, забирая данные обычным синхронным запросом. Этому посвящена отдельная страница-концепт: notify-and-pull-ipc.
3. IDL общеприняты; FTL обходится без них. В Fuchsia есть FIDL, в других системах - похожие генераторы. FTL заменяет весь слой IDL пятью фиксированными операциями: open, read, write, getattr, setattr, которые напрямую сопоставляются с аргументами системных вызовов. Никакой сериализации. Системный вызов отправки принимает два встроенных (inlined) аргумента, опциональный буфер тела и опциональный handle, а тип операции указывает ядру, что означает каждый слот. Переименование файла превращается в setattr; открытие слушающего TCP-сокета становится open("tcp:0.0.0.0:1234", MODE_LISTEN). Nuta называет это случайным переизобретением Plan 9 и отмечает, что os.Rename в Go на Plan 9 - это буквально запись атрибута файла. FTL отказывается от строгого правила "всё есть файл": пути могут быть произвольными handle'ами и не обязательно иметь форму файловой системы.
4. Pull, а не push; сначала peek, потом receive. Наивный драйвер проталкивает (push) пакеты на сервер TCP/IP по мере их поступления - и теперь проблема backpressure ложится на драйвер. FTL инвертирует схему: сервер TCP/IP отправляет запросы read, когда готов, а драйвер отвечает тем, что накопилось в буфере. Длина очереди сообщений ограничена числом запросов в обработке (in-flight), а не объёмом данных. Nuta проводит параллель с io_uring, которая тоже устроена по модели pull и ограничена количеством SQE. Путь приёма двухэтапный: channel_peek возвращает заголовок сообщения и непрозрачный recv_token, затем channel_receive(token, buf) копирует тело прямо в буфер назначения вызывающей стороны - без промежуточного копирования. Если получатель не готов, сообщение остаётся в очереди ядра, что передает backpressure клиенту без необходимости реализовывать отдельный протокол управления потоком в ядре. В реальном коде вызов peek совмещён с API потока событий (аналог epoll), поэтому лишнего системного вызова не возникает.
Почему это важно в 2026 году
Пост появился в год, когда изоляцию через передачу сообщений заново открывают под названиями "песочница для агентов" и "microVM". См. microvm-2026 и sandboxing-ai-agents - аргументы о базовом слое имеют ту же форму: разделяемое изменяемое состояние (пространство имён ядра, общая память) заменяется явной передачей сообщений через аппаратную границу. FTL относится скорее к области микроядер, чем к контейнерам, но pull-модель и паттерны notify-and-pull напрямую переносятся на любую систему, где производитель и потребитель пересекают границу доверия.
Пост также органично вписывается в более широкую дискуссию message-passing-vs-shared-memory. Формулировка Ли (Lee) 2006 года заключалась в том, что передача сообщений наследует тот же недетерминизм, что и разделяемое состояние. Архитектура FTL - это по большей части попытка устранить конкретные сценарии сбоев, присущие передаче сообщений: взаимные блокировки (notify-and-pull), backpressure (модель pull), накладные расходы на сериализацию (отказ от IDL) и двойное копирование (peek-then-receive). Она не устраняет фундаментальный недетерминизм - она лишь сужает область, где он может навредить.
В заключении отмечается, что вся архитектура формировалась под влиянием желания сделать async в Rust естественным, особенно в отношении cancellation safety. Nuta пишет, что готовит следующий пост об этой интеграции.
См. также
- revisit-microkernels - те же аргументы со стороны аппаратного обеспечения, где IOMMU вместе с кольцевым буфером в разделяемой памяти снимает претензии к накладным расходам из 90-х годов; там не затрагиваются проблемы управления потоком и deadlock'ов, которым посвящена большая часть этой страницы
- notify-and-pull-ipc - паттерн синхронного взаимодействия с уведомлениями как страница-концепт
- message-passing-vs-shared-memory - более широкий контекст координации конкурентности
- message-passing-shared-mutable-state - страница-источник Lee/Tu, стоящая за описанным выше
- microvm-2026 - те же аргументы о базовом слое на уровне VM-изоляции
- sandboxing-ai-agents - передача сообщений как способ изоляции в контексте песочниц для агентов
- seiya-nuta-blog - блог автора и контекст проектов (Resea, FTL)
- microkernel-ipc-design (источник)