Browse Source

chatgui: rework shutdown — main thread owns cleanup, remove glШбаls

Changes:
- UtunNode::requestStop() — async stop from any thread (m_stop+wakeup)
- UtunNode::finalize() — cleanup in main thread (etcp_router, chat_sync, chat_core, utun_instance, uasync)
- UtunNode::stop() — requestStop + join + finalize (for tray Quit path)
- Worker runLoop: only exits poll loop on m_stop, then emits stopped — no cleanup
- stopped() handler: calls finalize() in main thread, then qApp->quit()
- Tray Quit: calls requestStop(), stopped handler does finalize+quit
- Ctrl-C (Windows): SetConsoleCtrlHandler calls requestStop() via g_ctrl_node
- Ctrl-C (Linux): signal_handler calls requestStop() via g_currentNode
- Removed: g_shutdown, g_signal_ua, utun_node_signal_shutdown globals
topo_upd
Evgeny 2 months ago
parent
commit
fbaf58530f
  1. 6
      tools/chatgui/src/main.cpp
  2. 9
      tools/chatgui/src/mainwindow.cpp
  3. 1
      tools/chatgui/src/mainwindow.h
  4. 54
      tools/chatgui/transport/utun_node.cpp
  5. 3
      tools/chatgui/transport/utun_node.h

6
tools/chatgui/src/main.cpp

@ -9,13 +9,14 @@
#include "mainwindow.h"
#include "../db/db_manager.h"
#include "../transport/node_config.h"
#include "../transport/utun_node.h"
#ifdef _WIN32
extern "C" void utun_node_signal_shutdown(void);
static UtunNode* g_ctrl_node = nullptr;
static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType) {
if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
utun_node_signal_shutdown();
if (g_ctrl_node) g_ctrl_node->requestStop();
return TRUE;
}
return FALSE;
@ -92,6 +93,7 @@ int main(int argc, char *argv[]) {
w.show();
#ifdef _WIN32
g_ctrl_node = w.utunNode();
SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
#endif

9
tools/chatgui/src/mainwindow.cpp

@ -120,10 +120,11 @@ void MainWindow::setupNode() {
connect(m_node, &UtunNode::started, this, []() {
qDebug("UtunNode started");
});
connect(m_node, &UtunNode::stopped, this, []() {
connect(m_node, &UtunNode::stopped, this, [this]() {
qDebug("UtunNode stopped");
if (m_node) m_node->finalize();
qApp->quit();
});
connect(m_node, &UtunNode::stopped, qApp, &QApplication::quit);
if (!m_cfgDebugFile.isEmpty())
m_node->setDebugFile(m_cfgDebugFile);
@ -255,7 +256,9 @@ void MainWindow::setupTray() {
});
QAction *quitAction = m_trayMenu->addAction("Quit");
connect(quitAction, &QAction::triggered, qApp, &QApplication::quit);
connect(quitAction, &QAction::triggered, this, [this]() {
if (m_node) m_node->requestStop();
});
m_trayIcon->setContextMenu(m_trayMenu);

1
tools/chatgui/src/mainwindow.h

@ -36,6 +36,7 @@ public:
void onAutoConnectStatus(uint8_t status, uint16_t total, uint16_t totalNodes, uint16_t connected);
void onChannelPeersOnline(const char* ch_id, int ch_id_len, uint16_t online);
void reloadChannels();
UtunNode* utunNode() const { return m_node; }
private:
void setupUi();

54
tools/chatgui/transport/utun_node.cpp

@ -35,18 +35,9 @@ extern "C" {
static thread_local UtunNode* g_currentNode = nullptr;
static volatile sig_atomic_t g_shutdown = 0;
static struct UASYNC* g_signal_ua = nullptr;
static void signal_handler(int sig) {
(void)sig;
g_shutdown = 1;
if (g_signal_ua) uasync_wakeup(g_signal_ua);
}
extern "C" void utun_node_signal_shutdown(void) {
g_shutdown = 1;
if (g_signal_ua) uasync_wakeup(g_signal_ua);
if (g_currentNode) g_currentNode->requestStop();
}
UtunNode::UtunNode(QObject* parent) : QObject(parent) {}
@ -92,13 +83,32 @@ void UtunNode::setDebugCategories(const QString& categories) {
m_debugCategories = categories;
}
void UtunNode::requestStop() {
m_stop = true;
if (m_ua) uasync_wakeup(m_ua);
}
void UtunNode::stop() {
if (!m_running) return;
m_stop = true;
requestStop();
if (m_thread.joinable()) m_thread.join();
finalize();
m_running = false;
}
void UtunNode::finalize() {
if (!m_instance) return;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "finalize: cleanup start");
etcp_router_bind(m_instance, ETCP_RT_ID_CHAT, nullptr);
chat_sync_destroy(m_instance);
chat_core_destroy(m_instance);
utun_instance_destroy(m_instance);
m_instance = nullptr;
uasync_destroy(m_ua, 0);
m_ua = nullptr;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "finalize: cleanup done");
}
void UtunNode::send(uint64_t dstNodeId, const QByteArray& data) {
if (!m_instance) return;
struct ll_entry* entry = queue_entry_new(data.size());
@ -273,11 +283,13 @@ void UtunNode::runLoop() {
g_currentNode = nullptr;
return;
}
m_ua = ua;
m_instance = utun_instance_create(ua, m_configPath.toUtf8().constData());
if (!m_instance) {
QMetaObject::invokeMethod(this, [this] { emit error("utun_instance_create failed"); });
uasync_destroy(ua, 0);
m_ua = nullptr;
g_currentNode = nullptr;
return;
}
@ -319,6 +331,7 @@ void UtunNode::runLoop() {
utun_instance_destroy(m_instance);
m_instance = nullptr;
uasync_destroy(ua, 0);
m_ua = nullptr;
g_currentNode = nullptr;
return;
}
@ -336,31 +349,18 @@ void UtunNode::runLoop() {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chat_core + chat_sync initialized");
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "utun_node: entering poll loop");
g_signal_ua = ua;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
while (!m_stop && !g_shutdown) {
while (!m_stop) {
uasync_poll(ua, 100);
}
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: poll exit m_stop=%d g_shutdown=%d", (int)m_stop, (int)g_shutdown);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: poll exit m_stop=%d", (int)m_stop);
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
g_signal_ua = nullptr;
etcp_router_bind(m_instance, ETCP_RT_ID_CHAT, nullptr);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: etcp_router_unbind done");
chat_sync_destroy(m_instance);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: chat_sync_destroy done");
chat_core_destroy(m_instance);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: chat_core_destroy done");
utun_instance_destroy(m_instance);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: utun_instance_destroy done");
m_instance = nullptr;
uasync_destroy(ua, 0);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: uasync_destroy done, emitting stopped");
g_currentNode = nullptr;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "runLoop: emitting stopped");
QMetaObject::invokeMethod(this, [this] { emit stopped(); });
}

3
tools/chatgui/transport/utun_node.h

@ -21,8 +21,10 @@ public:
~UtunNode();
bool start(const QString& configPath);
void requestStop();
void stop();
bool isRunning() const { return m_running; }
void finalize();
void setDebugFile(const QString& path);
void setDbPath(const QString& path);
@ -49,6 +51,7 @@ private:
static void recvCallback(struct ETCP_CONN* conn, struct ll_entry* entry);
UTUN_INSTANCE* m_instance = nullptr;
struct UASYNC* m_ua = nullptr;
std::thread m_thread;
std::atomic<bool> m_running{false};
std::atomic<bool> m_stop{false};

Loading…
Cancel
Save