@ -261,6 +261,8 @@ static void install_crash_handlers(void) {
static void * instance_thread ( void * arg ) {
char * config_text = ( char * ) arg ;
int my_gen = g_generation ;
struct UASYNC * my_ua = NULL ; /* поток-локальная копия — для cleanup stale-потока */
struct UTUN_INSTANCE * my_inst = NULL ;
struct utun_config * config = parse_config_from_buf ( config_text , strlen ( config_text ) , " android " ) ;
u_free ( config_text ) ;
@ -269,6 +271,7 @@ static void* instance_thread(void* arg) {
install_crash_handlers ( ) ;
g_ua = uasync_create ( ) ;
my_ua = g_ua ;
if ( ! g_ua ) { IL_LOGE ( " uasync_create failed " ) ; free_config ( config ) ; __atomic_store_n ( & g_thread_running , 0 , __ATOMIC_RELEASE ) ; pthread_detach ( pthread_self ( ) ) ; return NULL ; }
standby_init ( g_ua ) ;
@ -280,6 +283,7 @@ static void* instance_thread(void* arg) {
ensure_keys ( config ) ;
g_inst = utun_instance_create_from_config ( g_ua , config ) ;
my_inst = g_inst ;
if ( ! g_inst ) {
IL_LOGE ( " utun_instance_create_from_config failed " ) ;
standby_deinit ( ) ;
@ -294,25 +298,8 @@ static void* instance_thread(void* arg) {
IL_LOGI ( " instance created, node_id=0x%016llx " , ( unsigned long long ) g_inst - > node_id ) ;
/* Open shared SQLite DB */
if ( g_db_path [ 0 ] & & ! g_inst - > topo_sqlite_db ) {
char db_file [ 512 ] ;
snprintf ( db_file , sizeof ( db_file ) , " %s/chats.db " , g_db_path ) ;
int rc = sqlite3_open_v2 ( db_file , & g_inst - > topo_sqlite_db ,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX , NULL ) ;
if ( rc = = SQLITE_OK & & g_inst - > topo_sqlite_db ) {
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA journal_mode=WAL " , NULL , NULL , NULL ) ;
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA foreign_keys=ON " , NULL , NULL , NULL ) ;
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA synchronous=NORMAL " , NULL , NULL , NULL ) ;
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA wal_autocheckpoint=10000 " , NULL , NULL , NULL ) ;
topo_node_sqlite_init ( g_inst - > topo_sqlite_db ) ;
IL_LOGI ( " SQLite opened %s " , db_file ) ;
} else {
IL_LOGE ( " SQLite open failed rc=%d " , rc ) ;
if ( g_inst - > topo_sqlite_db ) { sqlite3_close ( g_inst - > topo_sqlite_db ) ; g_inst - > topo_sqlite_db = NULL ; }
}
}
/* Shared SQLite DB открывается внутри utun_instance_init() → topo_groups_init()
( topo_group . c ) . Д в о й н о е о т к р ы т и е з д е с ь д а в а л о у т е ч к у с о е д и н е н и я н а к а ж д ы й р е с т а р т . */
/* Full init: db_sync, chat_core, chat_sync, init_connections */
if ( utun_instance_init ( g_inst ) ! = 0 ) {
IL_LOGE ( " utun_instance_init failed " ) ;
@ -369,13 +356,17 @@ static void* instance_thread(void* arg) {
g_inst ? g_inst - > connections : NULL ) ;
uasync_mark_stopped ( g_ua ) ;
__atomic_store_n ( & g_running , 0 , __ATOMIC_RELEASE ) ;
utun_instance_destroy ( g_inst ) ;
struct UTUN_INSTANCE * old_inst = g_inst ;
g_inst = NULL ;
utun_instance_destroy ( old_inst ) ;
my_inst = NULL ;
uasync_print_resources ( g_ua , " AFTER_DESTROY " ) ;
u_report_unfreed_blocks ( ) ;
standby_deinit ( ) ;
uasync_destroy ( g_ua , 0 ) ;
my_ua = NULL ;
g_ua = uasync_create ( ) ;
my_ua = g_ua ;
if ( ! g_ua ) { IL_LOGE ( " poll exit: uasync_create failed " ) ; break ; }
standby_init ( g_ua ) ;
@ -389,20 +380,11 @@ static void* instance_thread(void* arg) {
if ( ! config ) { IL_LOGE ( " poll exit: parse_config failed " ) ; break ; }
g_inst = utun_instance_create_from_config ( g_ua , config ) ;
my_inst = g_inst ;
if ( ! g_inst ) { IL_LOGE ( " poll exit: create_from_config failed " ) ; break ; }
chat_event_set_handler ( g_inst , chat_event_forward ) ;
char db_file [ 512 ] ;
snprintf ( db_file , sizeof ( db_file ) , " %s/chats.db " , g_db_path ) ;
int rc = sqlite3_open_v2 ( db_file , & g_inst - > topo_sqlite_db ,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX , NULL ) ;
if ( rc = = SQLITE_OK & & g_inst - > topo_sqlite_db ) {
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA journal_mode=WAL " , NULL , NULL , NULL ) ;
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA foreign_keys=ON " , NULL , NULL , NULL ) ;
sqlite3_exec ( g_inst - > topo_sqlite_db , " PRAGMA synchronous=NORMAL " , NULL , NULL , NULL ) ;
topo_node_sqlite_init ( g_inst - > topo_sqlite_db ) ;
} else { IL_LOGE ( " poll exit: SQLite open failed rc=%d " , rc ) ; break ; }
/* Shared SQLite DB открывается внутри utun_instance_init() (topo_group.c). */
if ( utun_instance_init ( g_inst ) ! = 0 ) { IL_LOGE ( " poll exit: utun_instance_init failed " ) ; break ; }
chat_core_sync_my_addresses ( g_inst ) ;
fire_local_sockets_event ( ) ;
@ -424,22 +406,29 @@ static void* instance_thread(void* arg) {
if ( my_gen = = g_generation ) {
__atomic_store_n ( & g_running , 0 , __ATOMIC_RELEASE ) ;
if ( g_inst ) {
chat_event_post ( g_inst , CHAT_EVT_SERVICE_STOPPED , NULL , 0 ) ;
utun_instance_destroy ( g_inst ) ;
if ( my_inst ) {
chat_event_post ( my_inst , CHAT_EVT_SERVICE_STOPPED , NULL , 0 ) ;
g_inst = NULL ;
utun_instance_destroy ( my_inst ) ;
my_inst = NULL ;
}
if ( g_ua ) {
if ( my _ua) {
standby_deinit ( ) ;
uasync_destroy ( g _ua, 0 ) ;
uasync_destroy ( my _ua, 0 ) ;
g_ua = NULL ;
my_ua = NULL ;
}
char * stale_cfg = ( char * ) __atomic_exchange_n ( & g_restart_config , NULL , __ATOMIC_ACQUIRE ) ;
u_free ( stale_cfg ) ;
u_report_unfreed_blocks ( ) ;
IL_LOGI ( " cleanup complete (gen=%d) " , my_gen ) ;
} else {
IL_LOGI ( " cleanup skipped — thread gen=%d but current gen=%d (stale thread) " , my_gen , g_generation ) ;
/* stale-поток: глобальные g_inst/g_ua уже принадлежат новому потоку,
н о с о б с т в е н н ы е о б ъ е к т ы э т о г о п о т о к а н а д о з а к р ы т ь , и н а ч е т е ч ё т fd . */
IL_LOGI ( " cleanup (stale thread gen=%d vs %d): destroying own inst=%p ua=%p to avoid fd leak " ,
my_gen , g_generation , ( void * ) my_inst , ( void * ) my_ua ) ;
if ( my_inst ) { utun_instance_destroy ( my_inst ) ; my_inst = NULL ; }
if ( my_ua ) { uasync_destroy ( my_ua , 0 ) ; my_ua = NULL ; }
}
__atomic_store_n ( & g_thread_running , 0 , __ATOMIC_RELEASE ) ;
pthread_mutex_lock ( & g_stop_mutex ) ;