--- nono/host/signalthread.cpp 2026/04/29 17:05:15 1.1.1.2 +++ nono/host/signalthread.cpp 2026/04/29 17:05:30 1.1.1.4 @@ -19,24 +19,12 @@ // ブロックするがペンディングにはなる、sigwait(3) はこのペンディングに反応 // する)。 // -// o SIGTERM を受け取ると UIMessage でメインスレッドに通知し、そこから安全に -// プロセスを終了させる。 -// -// o SIGINT(^C)、SIGTSTP(^Z)、SIGQUIT(^\) は HostCOM のうち stdio ドライバが -// 必要とするため動作を切り替える。HostCOM が stdio なら、これらのシグナル -// は処理せず、HostCOM スレッドにパイプで通知する。 -// HostCOM が stdio 以外なら、これらのシグナルは HostCOM に通知せず、 -// こちらで処理する。 +// o SIGTERM、SIGINT(^C) を受け取ると UIMessage でメインスレッドに通知し、 +// そこから安全にプロセスを終了させる。 // // o SIGHUP、SIGPIPE、SIGUSR1、SIGUSR2 はデフォルトがプロセス終了なので // ブロックして無視する。 // -// o SIGIO は、通常は非同期 I/O アクセスのハンドラとしてアプリケーションが -// これを使うことが想定されており、つまりライブラリが勝手に差し替えたり -// しないはずなので、これをこのスレッドへのメッセージ通知として使う。 -// SIGIO 発生時に特定のメンバ変数がセットされているとそれに従って -// アクションを起こす。 -// // Linux (Ubuntu 20.04) ではシグナルの配送が POSIX とは異なっているらしく、 // プロセスに届いたシグナルを sigwait しているスレッドに配送してくれない。 // glibc のマニュアルには記載があるようだ。 @@ -45,30 +33,27 @@ #include "signalthread.h" #include "uimessage.h" -#include #include -// グローバル参照用 -SignalThread *gSignalThread; +static void signal_handler(int signo); -void signal_handler(int signo); -void +static void signal_handler(int signo) { #if defined(__linux__) // Linux ではプロセスに届いたシグナルを自動でスレッドに配送して // くれないので、自前でやる必要があるようだ。 - if (gSignalThread) { - gSignalThread->Kill(signo); + SignalThread *sigthread = GetSignalThread(); + if (sigthread) { + sigthread->Kill(signo); } #endif } // コンストラクタ SignalThread::SignalThread() - : inherited("SignalThread") + : inherited(OBJ_SIGNAL_THREAD) { - wpipe = -1; sigemptyset(&waitset); } @@ -76,26 +61,18 @@ SignalThread::SignalThread() SignalThread::~SignalThread() { TerminateThread(); - gSignalThread = NULL; } // 常にブロックするシグナル集合 static std::vector siglist_always = { SIGHUP, // ignore + SIGINT, // プロセス終了 SIGPIPE, // ignore SIGTERM, // プロセス終了 - SIGIO, // コマンド通知に使う SIGUSR1, // ignore SIGUSR2, // ignore }; -// HostCOM が受け取るかどうかによって動作を変えるシグナル集合 -static std::vector siglist_com = { - SIGINT, // HostCOM (^C) - SIGQUIT, // HostCOM (^\) - SIGTSTP, // HostCOM (^Z) -}; - // スレッド開始 (override) // // SIGINT(^C) など緊急性の高いシグナルのブロック期間を極力短くするため、 @@ -110,9 +87,6 @@ SignalThread::StartThread() for (auto signo : siglist_always) { Mask(SIG_BLOCK, signo); } - for (auto signo : siglist_com) { - Mask(SIG_BLOCK, signo); - } // で、スレッドを開始。 return inherited::StartThread(); @@ -122,8 +96,9 @@ SignalThread::StartThread() void SignalThread::ThreadRun() { + SetThreadAffinityHint(AffinityClass::Light); + request_terminate = false; - request_wpipe = -1; for (;;) { int signo; @@ -149,63 +124,12 @@ SignalThread::ThreadRun() // ここからシグナル別の処理 switch (signo) { - case SIGIO: // コマンド - { - // 本来は無視するだけなので、ついでにこのスレッドに対する - // メッセージ通知として使用する。フラグが立ってなければ単に無視。 - // - // SIGIO 発生時に request_wpipe が非負なら、HostCOM からの - // パイプ接続もしくは切断の要求。 - int req = request_wpipe.exchange(-1); - if (req >= 0) { - if (loglevel >= 1) { - if (req == INT_MAX) { - putmsg(1, "SIGIO: HostCOM del"); - } else { - putmsg(1, "SIGIO: HostCOM add %d", req); - } - } - // HostCOM スレッドへのシグナル通知を変更 - ChangeCOM(req); - } - break; - } - - case SIGTERM: // SIGTERM なら即終了 + case SIGTERM: + case SIGINT: // メインスレッドから終了してもらう UIMessage::Post(UIMessage::APPEXIT); break; - case SIGINT: // パイプがあれば配送、なければここで処理 - if (wpipe >= 0) { - WriteSignal(wpipe, signo); - } else { - // メインスレッドから終了してもらう - UIMessage::Post(UIMessage::APPEXIT); - } - break; - - case SIGTSTP: // パイプがあれば配送、なければデフォルト動作 - case SIGQUIT: - if (wpipe >= 0) { - // パイプがあれば書き込んで通知。 - WriteSignal(wpipe, signo); - } else { - // パイプがなければ、 - // ここでデフォルト動作を起こしたい。 - - // 一旦解除して.. - Mask(SIG_UNBLOCK, signo); - - // シグナルを自身に送信。 - Kill(signo); - - // そして再度ブロックしておく。 - // こうしないと、2回目の ^Z が効かないとかになる。 - Mask(SIG_BLOCK, signo); - } - break; - default: // 他は無視する break; } @@ -221,80 +145,7 @@ SignalThread::Terminate() // フラグを立ててシグナルで通知 request_terminate = true; - Kill(SIGIO); -} - -// HostCOM スレッドへのパイプを接続する (HostCOM スレッドから呼ばれる) -void -SignalThread::AddPipe(int fd) -{ - putmsg(1, "AddPipe(fd=%d)", fd); - - if ((bool)thread == false) { - // HostCOM から呼ばれるが、起動時の初期設定は Init() フェーズ内の - // ため、その時点ではまだどちらもスレッドはない。 - // この場合は単にここで設定するだけでよい。 - ChangeCOM(fd); - } else { - // スレッド開始後なら、フラグを立ててシグナルで通知 - request_wpipe = fd; - Kill(SIGIO); - } -} - -// HostCOM スレッドへのパイプを削除する -void -SignalThread::DeletePipe() -{ - putmsg(1, "DeletePipe(current=%d)", wpipe); - - // フラグを立ててシグナルで通知 - request_wpipe = INT_MAX; - Kill(SIGIO); -} - -// シグナルをパイプに再配送する -void -SignalThread::WriteSignal(int wfd, int signo) -{ - char buf[1]; - int r; - - buf[0] = signo; - r = write(wpipe, buf, sizeof(buf)); - if (r < 0) { - // エラーが起きたパイプは閉じればいいか… - ChangeCOM(INT_MAX); - } -} - -// HostCOM スレッドとのパイプを接続/切断する。 -// SignalThread 側処理。 -void -SignalThread::ChangeCOM(int reqfd) -{ - // reqfd が INT_MAX なら現在のディスクリプタを切断。 - // そうでなければ、reqfd を接続。 - // そんな高頻度で投げないので運用上は問題にならないはず。 - - putmsg(1, "ChangeCOM(current=%d request=%d)", wpipe, reqfd); - - if (reqfd == INT_MAX) { - // パイプを切断してからシグナルのブロックを解除 - close(wpipe); - wpipe = -1; - - for (auto signo : siglist_com) { - Mask(SIG_UNBLOCK, signo); - } - } else { - // 必要なシグナルをブロックしてからパイプを接続 - for (auto signo : siglist_com) { - Mask(SIG_BLOCK, signo); - } - - wpipe = reqfd; - } + Kill(SIGTERM); } // SignalThread にシグナルを投げる (他スレッドからも使用可) @@ -359,11 +210,8 @@ SignalThread::Mask(int how, int signo) } while (0) CHECK(HUP); CHECK(INT); - CHECK(QUIT); CHECK(PIPE); CHECK(TERM); - CHECK(TSTP); - CHECK(IO); CHECK(USR1); CHECK(USR2);