Protect lifecycle producers and leave fatal signals to the platform
This commit is contained in:
1 parent
929df3b6cb
commit
5a4ddca190
3 files changed
+37
-99
No files matched your search
@@ -315,6 +315,10 @@ static int check_worker_requests(const char* directory) {
|
||||
REQUIRE(instance_lite_post(worker_payload_run, &payload, NULL, worker_payload_discard) == -1 && payload == -1);
|
||||
REQUIRE(!utun_bridge_clear_database(path));
|
||||
char keys[1100]; snprintf(keys, sizeof(keys), "%s/keys.conf", path); REQUIRE(!test_unlink(keys));
|
||||
const char* folders[] = {"member_files/.uploads", "member_files", "dm_pending", "dm_media"};
|
||||
for (unsigned i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) {
|
||||
snprintf(keys, sizeof(keys), "%s/%s", path, folders[i]); REQUIRE(!test_rmdir(keys));
|
||||
}
|
||||
REQUIRE(!test_rmdir(path));
|
||||
printf("[PASS] worker requests: real worker read, nested call, stopped queue discard and waiter cancellation\n");
|
||||
return 0;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*
|
||||
* UTUN выключен по умолчанию; [gui] utun_enabled=yes явно включает сервис при старте и рестарте.
|
||||
*/
|
||||
#define _GNU_SOURCE 1 /* dladdr (Linux); no-op on Android/bionic */
|
||||
#include "instance_lite.h"
|
||||
#include "utun_instance.h"
|
||||
#include "config_parser.h"
|
||||
@@ -42,9 +41,6 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <unwind.h>
|
||||
#include <dlfcn.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -348,55 +344,6 @@ static void on_link_status_changed(struct ETCP_CONN* conn, struct ETCP_LINK* lin
|
||||
fire_local_sockets_event();
|
||||
}
|
||||
|
||||
/* ── Crash handler ── */
|
||||
|
||||
static volatile int g_signal_caught = 0;
|
||||
static volatile int g_signal_num = 0;
|
||||
|
||||
struct crash_bt_state { void** frames; int count; int max; };
|
||||
|
||||
static _Unwind_Reason_Code crash_bt_cb(struct _Unwind_Context* ctx, void* arg) {
|
||||
struct crash_bt_state* st = (struct crash_bt_state*)arg;
|
||||
if (st->count < st->max) {
|
||||
void* pc = (void*)_Unwind_GetIP(ctx);
|
||||
if (pc) st->frames[st->count++] = pc;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
static void crash_signal_handler(int sig, siginfo_t* info, void* ctx) {
|
||||
(void)ctx;
|
||||
g_signal_caught = 1; g_signal_num = sig;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "CRASH signal=%d code=%d addr=%p thread still alive", sig, info->si_code, info->si_addr);
|
||||
void* frames[64];
|
||||
struct crash_bt_state st = { frames, 0, 64 };
|
||||
_Unwind_Backtrace(crash_bt_cb, &st);
|
||||
IL_LOGE("CRASH backtrace %d frames:", st.count);
|
||||
for (int i = 0; i < st.count; i++) {
|
||||
Dl_info dli;
|
||||
if (dladdr(frames[i], &dli) && dli.dli_sname) {
|
||||
IL_LOGE(" #%02d %p %s+%p (%s)", i, frames[i], dli.dli_sname,
|
||||
(void*)((char*)frames[i] - (char*)dli.dli_saddr),
|
||||
dli.dli_fname ? dli.dli_fname : "?");
|
||||
} else {
|
||||
IL_LOGE(" #%02d %p (no symbol)", i, frames[i]);
|
||||
}
|
||||
}
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
static void install_crash_handlers(void) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = crash_signal_handler;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
}
|
||||
|
||||
/* ── Thread function ── */
|
||||
static void log_active_sockets(struct UTUN_INSTANCE* inst, const char* label);
|
||||
|
||||
@@ -434,7 +381,6 @@ static void* instance_thread(void* arg) {
|
||||
if (!config) { IL_LOGE("parse_config_from_buf failed"); goto cleanup; }
|
||||
config->global.client_type = CLIENT_TYPE_MOBILE; /* Android — всегда мобильный узел (keepalive standby/normal) */
|
||||
|
||||
install_crash_handlers();
|
||||
if (ensure_keys(config)) {
|
||||
IL_LOGE("startup refused: Android identity is not saved");
|
||||
free_config(config);
|
||||
@@ -799,8 +745,8 @@ static int request_restart(const char* new_config_text, int regenerate_keys) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void instance_lite_restart(const char* new_config_text) {
|
||||
request_restart(new_config_text, 0);
|
||||
int instance_lite_restart(const char* new_config_text) {
|
||||
return request_restart(new_config_text, 0);
|
||||
}
|
||||
|
||||
/* Принимает владение ненулевым task при любом результате. Все данные команды находятся в том же выделении
|
||||
@@ -932,74 +878,62 @@ static void update_sockets_trampoline(void* arg) {
|
||||
u_free(cfg_text);
|
||||
return;
|
||||
}
|
||||
log_active_sockets(inst, "update OLD sockets");
|
||||
struct utun_config* cfg = parse_config_from_buf(cfg_text, strlen(cfg_text), "android-update");
|
||||
u_free(cfg_text);
|
||||
if (!cfg) { IL_LOGE("update_sockets: parse_config_from_buf failed"); return; }
|
||||
auto_socket_reload_config(inst, cfg); /* cfg владеет auto_socket: servers переносятся, остальное освобождается */
|
||||
}
|
||||
|
||||
void instance_lite_update_sockets(const char* config_text) {
|
||||
if (!config_text) return;
|
||||
struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE);
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
|
||||
int running = __atomic_load_n(&g_running, __ATOMIC_ACQUIRE);
|
||||
|
||||
/* Диагностика смены сети: какие сокеты/адреса были → какие будут (без полного рестарта). */
|
||||
log_active_sockets(inst, "update OLD sockets");
|
||||
int instance_lite_update_sockets(const char* config_text) {
|
||||
if (!config_text) { IL_LOGE("update_sockets: config is NULL"); return -1; }
|
||||
log_config_servers(config_text, "update NEW config");
|
||||
|
||||
if (!ua || !inst || !running) {
|
||||
IL_LOGE("update_sockets: instance not running (ua=%p inst=%p running=%d) — update dropped (no fallback restart)",
|
||||
(void*)ua, (void*)inst, running);
|
||||
return;
|
||||
}
|
||||
char* copy = u_strdup(config_text);
|
||||
if (!copy) { IL_LOGE("update_sockets: u_strdup failed"); return; }
|
||||
uasync_post(ua, update_sockets_trampoline, copy);
|
||||
if (!copy) { IL_LOGE("update_sockets: config allocation failed"); return -1; }
|
||||
if (instance_lite_post(update_sockets_trampoline, copy, NULL, NULL)) {
|
||||
IL_LOGE("update_sockets: core not ready, update rejected"); u_free(copy); return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ── Health check ping ── */
|
||||
|
||||
static volatile int g_ping_id = 0;
|
||||
static volatile int g_pong_id = 0;
|
||||
static uint64_t g_ping_id;
|
||||
static uint64_t g_pong_id;
|
||||
|
||||
static void ping_trampoline(void* arg) {
|
||||
(void)arg;
|
||||
g_pong_id = g_ping_id;
|
||||
__atomic_store_n(&g_pong_id, *(uint64_t*)arg, __ATOMIC_RELEASE);
|
||||
u_free(arg);
|
||||
}
|
||||
|
||||
void instance_lite_ping(void) {
|
||||
struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE);
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
|
||||
if (!ua || !inst) return;
|
||||
g_ping_id++;
|
||||
uasync_post(ua, ping_trampoline, NULL);
|
||||
if (!instance_lite_is_running()) return;
|
||||
uint64_t* id = u_malloc(sizeof(*id));
|
||||
if (!id) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Android health ping allocation failed"); return; }
|
||||
*id = __atomic_add_fetch(&g_ping_id, 1, __ATOMIC_ACQ_REL);
|
||||
if (instance_lite_post(ping_trampoline, id, NULL, NULL)) u_free(id);
|
||||
}
|
||||
|
||||
int instance_lite_is_responsive(void) {
|
||||
struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE);
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
|
||||
if (!ua || !inst || !__atomic_load_n(&g_running, __ATOMIC_ACQUIRE)) return 0;
|
||||
if (g_ping_id == 0) return 0;
|
||||
return (g_pong_id == g_ping_id) ? 1 : 0;
|
||||
uint64_t ping = __atomic_load_n(&g_ping_id, __ATOMIC_ACQUIRE);
|
||||
return instance_lite_is_running() && ping && __atomic_load_n(&g_pong_id, __ATOMIC_ACQUIRE) == ping;
|
||||
}
|
||||
|
||||
static void collect_conn_list_run(void* unused) {
|
||||
(void)unused;
|
||||
chat_core_collect_conn_list_trampoline(instance_lite_get_instance());
|
||||
}
|
||||
|
||||
void instance_lite_collect_conn_list(void) {
|
||||
struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE);
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
|
||||
if (!ua || !inst) return;
|
||||
uasync_post(ua, chat_core_collect_conn_list_trampoline, inst);
|
||||
if (instance_lite_post(collect_conn_list_run, NULL, NULL, NULL))
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Android connection list request rejected: core not ready");
|
||||
}
|
||||
|
||||
void instance_lite_collect_conn_metrics(uint64_t peer_node_id) {
|
||||
struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE);
|
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
|
||||
if (!ua || !inst) return;
|
||||
struct chat_node_arg* arg = (struct chat_node_arg*)u_malloc(sizeof(struct chat_node_arg));
|
||||
if (!arg) return;
|
||||
arg->inst = inst;
|
||||
if (!arg) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Android connection metrics allocation failed"); return; }
|
||||
arg->node_id = peer_node_id;
|
||||
uasync_post(ua, chat_core_collect_conn_metrics_trampoline, arg);
|
||||
if (instance_lite_post(chat_core_collect_conn_metrics_trampoline, arg, &arg->inst, NULL)) u_free(arg);
|
||||
}
|
||||
|
||||
int instance_lite_is_running(void) {
|
||||
|
||||
@@ -110,12 +110,12 @@ int instance_lite_configure_radio(int64_t request_id, const int* values, instanc
|
||||
* При инициализации ставит запрос в очередь; при завершившемся worker делает join/start.
|
||||
* Обновление асинхронное; старые handles утрачивают силу.
|
||||
* Stop имеет приоритет перед ожидающим restart. Последний ещё не взятый worker запрос заменяет предыдущий. */
|
||||
void instance_lite_restart(const char* new_config_text);
|
||||
int instance_lite_restart(const char* new_config_text); /* 0 — запрос принят, -1 — отказ с логом. */
|
||||
|
||||
/* Лёгкое обновление сокетов (auto_sockets=android): перечитывает [server] секции
|
||||
* из нового конфига и сверяет сокеты без полного рестарта. Posts to uasync thread.
|
||||
* Если ядро не запущено — только логирует ошибку и дропает вызов. */
|
||||
void instance_lite_update_sockets(const char* config_text);
|
||||
* 0 — копия принята worker, -1 — ошибка памяти/неготовое ядро с логом. */
|
||||
int instance_lite_update_sockets(const char* config_text);
|
||||
|
||||
/* Поставить локальный ping в uasync (не сетевой). is_responsive=1 после исполнения последнего ping;
|
||||
* до первого ping/при остановке возвращает 0. Встроенного ожидания и проверки таймаута нет. */
|
||||
|
||||
Reference in new issue
Block a user