From: Szymon Lukasz <[email protected]>

Block SIGWINCH, so it is delivered only via signalfd.
Install a handler that uses NotifierList to tell
interested parties about SIGWINCH delivery.

Signed-off-by: Szymon Lukasz <[email protected]>
[Filip: add sigwinch_remove_notifier, call it in curses_cleanup]
Signed-off-by: Filip Hejsek <[email protected]>
Reviewed-by: Marc-André Lureau <[email protected]>
Message-ID: <[email protected]>
---
 include/qemu/main-loop.h |  5 +++++
 ui/curses.c              | 21 +++++++++++++++------
 util/main-loop.c         | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 8c1241a2c11c..533d4c2be413 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -449,4 +449,9 @@ typedef struct MainLoopPoll {
 void main_loop_poll_add_notifier(Notifier *notify);
 void main_loop_poll_remove_notifier(Notifier *notify);
 
+#ifndef _WIN32
+void sigwinch_add_notifier(Notifier *n);
+void sigwinch_remove_notifier(Notifier *n);
+#endif
+
 #endif
diff --git a/ui/curses.c b/ui/curses.c
index 4db32b6168d6..9079bfbee469 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -33,6 +33,7 @@
 #include <iconv.h>
 
 #include "qapi/error.h"
+#include "qemu/main-loop.h"
 #include "qemu/module.h"
 #include "ui/console.h"
 #include "ui/input.h"
@@ -149,7 +150,7 @@ static void curses_resize(DisplayChangeListener *dcl,
 }
 
 #if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE)
-static volatile sig_atomic_t got_sigwinch;
+static bool got_sigwinch;
 static void curses_winch_check(void)
 {
     struct winsize {
@@ -172,21 +173,28 @@ static void curses_winch_check(void)
     invalidate = 1;
 }
 
-static void curses_winch_handler(int signum)
+static void curses_winch_handler(Notifier *n, void *data)
 {
     got_sigwinch = true;
 }
 
+static Notifier winch_notifier = {
+    .notify = curses_winch_handler
+};
+
 static void curses_winch_init(void)
 {
-    struct sigaction old, winch = {
-        .sa_handler  = curses_winch_handler,
-    };
-    sigaction(SIGWINCH, &winch, &old);
+    sigwinch_add_notifier(&winch_notifier);
+}
+
+static void curses_winch_cleanup(void)
+{
+    sigwinch_remove_notifier(&winch_notifier);
 }
 #else
 static void curses_winch_check(void) {}
 static void curses_winch_init(void) {}
+static void curses_winch_cleanup(void) {}
 #endif
 
 static void curses_cursor_position(DisplayChangeListener *dcl,
@@ -417,6 +425,7 @@ static void curses_cleanup(void)
         return;
     }
 
+    curses_winch_cleanup();
     endwin();
     qemu_console_unregister_listener(dcl);
     g_clear_pointer(&dcl, g_free);
diff --git a/util/main-loop.c b/util/main-loop.c
index 65e5dbcc941b..e59af0e270e4 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -100,6 +100,7 @@ static int qemu_signal_init(Error **errp)
     sigaddset(&set, SIGIO);
     sigaddset(&set, SIGALRM);
     sigaddset(&set, SIGBUS);
+    sigaddset(&set, SIGWINCH);
     /* SIGINT cannot be handled via signalfd, so that ^C can be used
      * to interrupt QEMU when it is being run under gdb.  SIGHUP and
      * SIGTERM are also handled asynchronously, even though it is not
@@ -124,6 +125,38 @@ static int qemu_signal_init(Error **errp)
     return 0;
 }
 
+static NotifierList sigwinch_notifiers =
+    NOTIFIER_LIST_INITIALIZER(sigwinch_notifiers);
+
+static void sigwinch_handler(int signum)
+{
+    notifier_list_notify(&sigwinch_notifiers, NULL);
+}
+
+void sigwinch_add_notifier(Notifier *n)
+{
+    if (notifier_list_empty(&sigwinch_notifiers)) {
+        struct sigaction action = {
+            .sa_handler = sigwinch_handler,
+        };
+        sigaction(SIGWINCH, &action, NULL);
+    }
+
+    notifier_list_add(&sigwinch_notifiers, n);
+}
+
+void sigwinch_remove_notifier(Notifier *n)
+{
+    notifier_remove(n);
+
+    if (notifier_list_empty(&sigwinch_notifiers)) {
+        struct sigaction action = {
+            .sa_handler = SIG_DFL,
+        };
+        sigaction(SIGWINCH, &action, NULL);
+    }
+}
+
 #else /* _WIN32 */
 
 static int qemu_signal_init(Error **errp)

-- 
2.56.0.116.g6de20f6092dc


Reply via email to