wreadln, screen_utils: avoid busy looping wgetch()
authorMax Kellermann <max@musicpd.org>
Tue, 9 Apr 2019 21:25:06 +0000 (23:25 +0200)
committerMax Kellermann <max@musicpd.org>
Tue, 9 Apr 2019 21:25:06 +0000 (23:25 +0200)
boost::asio switches STDIN_FILENO to non-blocking mode, causing
wgetch() to always return immediately, causing EAGAIN if no key press
is pending.  This causes wreadln() and screen_getch() to busy-loop.

This commit adds poll() calls to idle while no key press is pending.

Closes https://github.com/MusicPlayerDaemon/ncmpc/issues/50

NEWS
src/WaitUserInput.hxx
src/screen_utils.cxx
src/wreadln.cxx

diff --git a/NEWS b/NEWS
index fe1578e..ea69189 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,6 @@
 ncmpc 0.34 - not yet released
 * fix high CPU usage in key bindings check
+* fix high CPU usage during text input
 * fix background color "none"
 * adapt to Boost 1.70.0 API changes
 
index e6a29a1..8306341 100644 (file)
@@ -36,6 +36,10 @@ public:
                return Poll(0);
        }
 
+       bool Wait() noexcept {
+               return Poll(-1);
+       }
+
 private:
        bool Poll(int timeout) noexcept {
                return poll(&pfd, 1, timeout) > 0;
index 6da4239..ba041df 100644 (file)
 #include "wreadln.hxx"
 #include "ncmpc.hxx"
 
+#ifndef _WIN32
+#include "WaitUserInput.hxx"
+#endif
+
 #include <mpd/client.h>
 
 #include <string.h>
@@ -64,8 +68,23 @@ screen_getch(const char *prompt) noexcept
        echo();
        curs_set(1);
 
+#ifndef _WIN32
+       WaitUserInput wui;
+#endif
+
        int key;
-       while (ignore_key(key = wgetch(w))) {}
+       do {
+               key = wgetch(w);
+
+#ifndef _WIN32
+               if (key == ERR && errno == EAGAIN) {
+                       if (wui.Wait())
+                               continue;
+                       else
+                               break;
+               }
+#endif
+       } while (ignore_key(key));
 
        noecho();
        curs_set(0);
index f036f7f..853adfd 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#if (defined(HAVE_CURSES_ENHANCED) || defined(ENABLE_MULTIBYTE)) && !defined(_WIN32)
+#ifndef _WIN32
 #include "WaitUserInput.hxx"
 #endif
 
@@ -318,10 +318,23 @@ _wreadln(WINDOW *w,
                wr.Paint();
        }
 
+#ifndef _WIN32
+       WaitUserInput wui;
+#endif
+
        int key = 0;
        while (key != 13 && key != '\n') {
                key = wgetch(w);
 
+#ifndef _WIN32
+               if (key == ERR && errno == EAGAIN) {
+                       if (wui.Wait())
+                               continue;
+                       else
+                               break;
+               }
+#endif
+
                /* check if key is a function key */
                for (size_t i = 0; i < 63; i++)
                        if (key == (int)KEY_F(i)) {