93 lines
9.2 KiB
Markdown
93 lines
9.2 KiB
Markdown
# Жизненный цикл ядра и сервисов
|
||
|
||
CLI выполняет daemon fork до создания `UASYNC`, SQLite, сокетов и фоновых потоков.
|
||
Сервисы и их workers создаются уже в дочернем процессе. Родитель ждёт подтверждения
|
||
успешной инициализации и записи PID-файла; ошибка старта возвращается вызывающему.
|
||
`test_daemon_worker` проверяет настоящий запуск без `-f`, наличие дискового потока,
|
||
штатный SIGTERM и ненулевой статус launcher при ошибке PID-файла.
|
||
|
||
Все операции выполняются в потоке единственного `UASYNC` экземпляра, вне callbacks
|
||
останавливаемых модулей. GUI передаёт команды в этот поток.
|
||
|
||
```c
|
||
struct UTUN_INSTANCE* inst = utun_instance_create_from_str(ua, config);
|
||
if (!inst || utun_core_start(inst) < 0) /* обработать ошибку */;
|
||
if (chat_service_start(inst) < 0) /* обработать ошибку */;
|
||
if (utun_service_start(inst) < 0) /* обработать ошибку */;
|
||
|
||
chat_service_stop(inst); /* UTUN продолжает работать */
|
||
chat_service_start(inst); /* загружает сохранённые каналы */
|
||
utun_service_stop(inst); /* чат продолжает работать */
|
||
utun_instance_destroy(inst);
|
||
```
|
||
|
||
`utun_instance_init()` — сокращение для запуска ядра, UTUN и чата, если чат включён
|
||
в конфигурации. Desktop GUI и Android запускают ядро и чат явно, без UTUN.
|
||
Повторный start работающего сервиса и повторный stop допустимы. Ошибка старта
|
||
сервиса откатывает созданные им ресурсы. `utun_instance_stop()` останавливает цикл
|
||
приложения; освобождение ядра выполняет `utun_instance_destroy()`.
|
||
|
||
| Владелец | Ресурсы |
|
||
|---|---|
|
||
| Ядро | Идентичность узла, реестр узлов и групп, SQLite, транспортные сокеты, NCD, маршрутизатор, общая репликация, время, мониторинг |
|
||
| UTUN | Группа UTUN, запросы соединений из конфигурации, DATA binding, TUN, системные маршруты, NAT transport |
|
||
| Чат | CHAT-группы, запросы подключения и join, экземпляры синхронизации каналов, chat API, медиа, личные сообщения, звонки и headless API |
|
||
| Группа | Сессии пиров, её маршруты и логические каналы, планировщик подключения и recovery |
|
||
| Сессия пира группы | NCD handle с момента CONNECTING, согласованные эпохи, состояние обмена таблицей, очередь отправки |
|
||
|
||
SQLite открывается ядром один раз: `db_path/chats.db`, либо `:memory:`, если путь
|
||
не задан. Остановка чата сохраняет каналы и сообщения в этой БД. В варианте
|
||
`:memory:` данные сохраняются только до уничтожения ядра.
|
||
|
||
Общий транспорт живёт, пока есть его владельцы. Закрытие запроса одной группы
|
||
не разрывает соединение, нужное другой группе. При остановке группы отменяются
|
||
её планировщики, запросы, таймеры и ожидания очередей; отправляется LEAVE,
|
||
закрываются логические каналы маршрутизатора и удаляется её ожидающий транзит
|
||
на общих соединениях. Транзит других групп сохраняется. Отложенный LEAVE может временно
|
||
удерживать транспорт самостоятельно, не обращаясь к уже удалённой группе.
|
||
|
||
Остановка чата сначала прекращает внешние команды и фоновые задания, затем
|
||
закрывает медиа и сервисы, синхронизацию и группы, после чего освобождает chat core.
|
||
`media_async_destroy()` дожидается завершения native workers и вызывает каждый
|
||
ожидающий callback с `MEDIA_ASYNC_CANCELLED`, пока его контекст ещё существует.
|
||
Worker резервирует completion до запуска и передаёт его через `uasync_post_reserved`;
|
||
периодического polling нет. Destroy выполняется вне callbacks uasync, после join
|
||
отменяет pending post и завершает done ровно один раз. Uasync живёт до конца этой очистки.
|
||
Результаты отменённых задач не записываются в БД. Это синхронное ожидание: длительное
|
||
транскодирование или распознавание речи может задержать stop; принудительного
|
||
прерывания этих библиотек нет.
|
||
|
||
Статус транспорта UP подтверждает восстановление физического пути. READY сессии
|
||
группы означает согласованный JOIN/ACCEPT и завершённый обмен её таблицей; именно
|
||
его ждёт recovery. REINIT меняет эпохи обмена, сохраняя рабочие маршруты. Эпохи
|
||
защищают от сообщений старой сессии и не задают срок жизни маршрута.
|
||
|
||
Проверки: `test_services` проверяет независимый stop/start, общий NCD в CONNECTING,
|
||
сохранение идентичности/сокетов/БД, повторную загрузку каналов, отмену workers,
|
||
заблокированного медиа-потока, транзита и ожиданий заменённой очереди. `test_chat_join_e2e`
|
||
проверяет join и распространение membership между узлами без UTUN-сервиса.
|
||
|
||
В Android звонковой сессией владеет `CallController` уровня приложения; события
|
||
ядра и команды Telecom обрабатываются один раз в main thread, без повторного
|
||
проигрывания событий при создании ViewModel. UI получает `StateFlow` и передаёт
|
||
пользовательские команды. `CallService` владеет `CallAudioEngine` и частичным
|
||
wake lock: перед исходящим вызовом или принятием входящего запускается foreground
|
||
режим `phoneCall|microphone`, затем сигналинг и аудио. Завершение сначала
|
||
останавливает I/O и дожидается аудиопотоков, затем освобождает native-аудио,
|
||
wake lock и сервис. Перед `NativeLib.stop/restart/destroy` выполняется тот же
|
||
порядок; новый звонок разрешается после `SERVICE_STARTED` нового ядра.
|
||
|
||
Активность ядра задаётся явно: видимая Activity или незавершённый звонок удерживают
|
||
ACTIVE и выключают Android standby. Состояние не истекает по таймеру. После
|
||
завершения звонка в фоне возвращается standby; экран может гаснуть во время
|
||
разговора независимо от частичного wake lock сервиса.
|
||
|
||
`utun_set_client_activity()` в сборке с `UTUN_HAVE_STANDBY` применяет фактический
|
||
режим duty-cycle до рассылки событий активности; JNI не переключает его отдельно.
|
||
Повторная команда не перезапускает фазу и анонсы, но первый фоновый запуск включает
|
||
standby даже при начальном `client_activity=STANDBY`. Keepalive подписан на режим
|
||
и фазы самого standby; новые UDP/TCP-линки сразу анонсируют текущую фазу после
|
||
handshake. Пробуждение по таймеру и внешней сети сначала сообщает ACTIVE-окно
|
||
пирам, затем запускает ожидающие задачи. При выходе сначала восстанавливаются
|
||
линки; deinit отменяет ожидающие задачи и очищает подписки старого ядра.
|