Fix Ctrl+C not terminating the C backend

Two issues:
- signal() on Linux sets SA_RESTART by default, causing sleep(1) to be
  restarted after the signal handler runs. Switch to sigaction() with no
  SA_RESTART flag and replace sleep(1) with pause() so the main thread
  wakes and exits immediately on SIGINT/SIGTERM.
- close(sock_fd) is not guaranteed to unblock another thread blocked in
  accept() on that fd. Add shutdown(SHUT_RDWR) before close() in
  socket_server_stop() for both the listening socket and the client
  socket, which reliably wakes blocked accept() and read() calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 04:22:07 +00:00
parent 9b45905d80
commit ce44dbaad4
2 changed files with 13 additions and 5 deletions

View File

@@ -164,7 +164,7 @@ static void on_disconnect(void *ctx) {
/* ── Signal handler ───────────────────────────────────────────────── */ /* ── Signal handler ───────────────────────────────────────────────── */
static volatile int g_running = 1; static volatile sig_atomic_t g_running = 1;
static void on_signal(int sig) { (void)sig; g_running = 0; } static void on_signal(int sig) { (void)sig; g_running = 0; }
/* ── Entry point ──────────────────────────────────────────────────── */ /* ── Entry point ──────────────────────────────────────────────────── */
@@ -190,12 +190,14 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
signal(SIGINT, on_signal); struct sigaction sa = { .sa_handler = on_signal, .sa_flags = 0 };
signal(SIGTERM, on_signal); sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
fprintf(stderr, "midi-sequencer ready, waiting for node client\n"); fprintf(stderr, "midi-sequencer ready, waiting for node client\n");
while (g_running) { while (g_running) {
sleep(1); pause(); /* sleep until any signal; returns immediately on SIGINT/SIGTERM */
} }
fprintf(stderr, "midi-sequencer shutting down\n"); fprintf(stderr, "midi-sequencer shutting down\n");

View File

@@ -127,9 +127,15 @@ int socket_server_start(Socket_Server *srv, const char *path,
void socket_server_stop(Socket_Server *srv) { void socket_server_stop(Socket_Server *srv) {
atomic_store(&srv->running, 0); atomic_store(&srv->running, 0);
/* shutdown before close to reliably unblock accept() in accept_thread */
shutdown(srv->sock_fd, SHUT_RDWR);
close(srv->sock_fd); close(srv->sock_fd);
int fd = atomic_exchange(&srv->client_fd, -1); int fd = atomic_exchange(&srv->client_fd, -1);
if (fd >= 0) close(fd); if (fd >= 0) {
/* shutdown before close to reliably unblock read() in read_thread */
shutdown(fd, SHUT_RDWR);
close(fd);
}
pthread_join(srv->accept_thread, NULL); pthread_join(srv->accept_thread, NULL);
pthread_join(srv->read_thread, NULL); pthread_join(srv->read_thread, NULL);
pthread_mutex_destroy(&srv->write_mutex); pthread_mutex_destroy(&srv->write_mutex);