diff --git a/src/lib/barrier/App.cpp b/src/lib/barrier/App.cpp index f4293b63..91238779 100644 --- a/src/lib/barrier/App.cpp +++ b/src/lib/barrier/App.cpp @@ -64,7 +64,8 @@ App::App(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, A m_createTaskBarReceiver(createTaskBarReceiver), m_appUtil(events), m_ipcClient(nullptr), - m_socketMultiplexer(nullptr) + m_socketMultiplexer(nullptr), + m_stdin(nullptr) { assert(s_instance == nullptr); s_instance = this; @@ -74,6 +75,10 @@ App::~App() { s_instance = nullptr; delete m_args; + + if (m_stdin) { + delete(m_stdin); + } } void @@ -216,6 +221,14 @@ App::cleanupIpcClient() delete m_ipcClient; } +void +App::initStdinListen() +{ +#if !defined(_WIN32) + m_stdin = new StdinListen(m_events); +#endif +} + void App::handleIpcMessage(const Event& e, void*) { diff --git a/src/lib/barrier/App.h b/src/lib/barrier/App.h index b7c77a00..5ceaf6a0 100644 --- a/src/lib/barrier/App.h +++ b/src/lib/barrier/App.h @@ -23,6 +23,7 @@ #include "base/String.h" #include "base/Log.h" #include "base/EventQueue.h" +#include "base/StdinListen.h" #include "common/common.h" #if SYSAPI_WIN32 @@ -106,6 +107,7 @@ private: protected: void initIpcClient(); void cleanupIpcClient(); + void initStdinListen(); void runEventsLoop(void*); IArchTaskBarReceiver* m_taskBarReceiver; @@ -120,6 +122,7 @@ private: ARCH_APP_UTIL m_appUtil; IpcClient* m_ipcClient; SocketMultiplexer* m_socketMultiplexer; + StdinListen* m_stdin; }; class MinimalApp : public App { diff --git a/src/lib/barrier/ClientApp.cpp b/src/lib/barrier/ClientApp.cpp index 15416f60..8a97f5e9 100644 --- a/src/lib/barrier/ClientApp.cpp +++ b/src/lib/barrier/ClientApp.cpp @@ -455,6 +455,11 @@ ClientApp::mainLoop() initIpcClient(); } + // setup polling for stdin if not running in daemon mode + if (!argsBase().m_daemon) { + initStdinListen(); + } + // run event loop. if startClient() failed we're supposed to retry // later. the timer installed by startClient() will take care of // that. diff --git a/src/lib/barrier/ServerApp.cpp b/src/lib/barrier/ServerApp.cpp index fbb5092c..42b3792b 100644 --- a/src/lib/barrier/ServerApp.cpp +++ b/src/lib/barrier/ServerApp.cpp @@ -748,6 +748,11 @@ ServerApp::mainLoop() initIpcClient(); } + // setup polling for stdin if not running in daemon mode + if (!argsBase().m_daemon) { + initStdinListen(); + } + // handle hangup signal by reloading the server's configuration ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL); m_events->adoptHandler(m_events->forServerApp().reloadConfig(), diff --git a/src/lib/base/EventQueue.cpp b/src/lib/base/EventQueue.cpp index b17e35bf..bb5f07fc 100644 --- a/src/lib/base/EventQueue.cpp +++ b/src/lib/base/EventQueue.cpp @@ -201,23 +201,11 @@ EventQueue::adoptBuffer(IEventQueueBuffer* buffer) } } -bool -EventQueue::parent_requests_shutdown() const -{ - char ch; - return m_parentStream.try_read_char(ch) && ch == ShutdownCh; -} - bool EventQueue::getEvent(Event& event, double timeout) { Stopwatch timer(true); retry: - // before handling any events make sure we don't need to shutdown - if (parent_requests_shutdown()) { - event = Event(Event::kQuit); - return false; - } // if no events are waiting then handle timers and then wait while (m_buffer->isEmpty()) { // handle timers first diff --git a/src/lib/base/EventQueue.h b/src/lib/base/EventQueue.h index 97e7fba7..d4fb6ffd 100644 --- a/src/lib/base/EventQueue.h +++ b/src/lib/base/EventQueue.h @@ -26,7 +26,6 @@ #include "base/Stopwatch.h" #include "common/stdmap.h" #include "common/stdset.h" -#include "base/NonBlockingStream.h" #include @@ -73,7 +72,6 @@ private: bool hasTimerExpired(Event& event); double getNextTimerTimeout() const; void addEventToBuffer(const Event& event); - bool parent_requests_shutdown() const; private: class Timer { @@ -186,7 +184,6 @@ private: Mutex* m_readyMutex; CondVar* m_readyCondVar; std::queue m_pending; - NonBlockingStream m_parentStream; }; #define EVENT_TYPE_ACCESSOR(type_) \ diff --git a/src/lib/base/NonBlockingStream.cpp b/src/lib/base/StdinListen.cpp similarity index 59% rename from src/lib/base/NonBlockingStream.cpp rename to src/lib/base/StdinListen.cpp index d44add15..3612319d 100644 --- a/src/lib/base/NonBlockingStream.cpp +++ b/src/lib/base/StdinListen.cpp @@ -17,44 +17,47 @@ #if !defined(_WIN32) -#include "base/NonBlockingStream.h" +#include "base/StdinListen.h" +#include "../gui/src/ShutdownCh.h" #include // tcgetattr/tcsetattr, read #include // tcgetattr/tcsetattr -#include -#include -#include -NonBlockingStream::NonBlockingStream(int fd) : - _fd(fd) +StdinListen::StdinListen(IEventQueue* events) : + m_events(events), + m_thread(NULL) { // disable ICANON & ECHO so we don't have to wait for a newline // before we get data (and to keep it from being echoed back out) termios ta; - tcgetattr(fd, &ta); + tcgetattr(STDIN_FILENO, &ta); _p_ta_previous = new termios(ta); ta.c_lflag &= ~(ICANON | ECHO); - tcsetattr(fd, TCSANOW, &ta); + tcsetattr(STDIN_FILENO, TCSANOW, &ta); - // prevent IO from blocking so we can poll (read()) - int _cntl_previous = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, _cntl_previous | O_NONBLOCK); + m_thread = new Thread(new TMethodJob( + this, &StdinListen::stdinThread)); } -NonBlockingStream::~NonBlockingStream() +StdinListen::~StdinListen() { - tcsetattr(_fd, TCSANOW, _p_ta_previous); - fcntl(_fd, F_SETFL, _cntl_previous); + tcsetattr(STDIN_FILENO, TCSANOW, _p_ta_previous); delete _p_ta_previous; } -bool NonBlockingStream::try_read_char(char &ch) const +void +StdinListen::stdinThread(void *) { - int result = read(_fd, &ch, 1); - if (result == 1) - return true; - assert(result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)); - return false; + char ch; + + while (1) { + if (read(STDIN_FILENO, &ch, 1) == 1) { + if (ch == ShutdownCh) { + m_events->addEvent(Event(Event::kQuit)); + break; + } + } + } } -#endif // !defined(_WIN32) +#endif // !defined(_WIN32) \ No newline at end of file diff --git a/src/lib/base/NonBlockingStream.h b/src/lib/base/StdinListen.h similarity index 61% rename from src/lib/base/NonBlockingStream.h rename to src/lib/base/StdinListen.h index 4c27762a..8491ba59 100644 --- a/src/lib/base/NonBlockingStream.h +++ b/src/lib/base/StdinListen.h @@ -17,33 +17,34 @@ #pragma once -// windows doesn't have a unistd.h so this class won't work as-written. -// at the moment barrier doesn't need this functionality on windows so -// it's left as a stub to be optimized out #if defined(_WIN32) -class NonBlockingStream +class StdinListen { public: - bool try_read_char(char &ch) const { return false; }; + void stdinThread(void*) {}; }; -#else // non-windows platforms +#else + +#include "base/IEventQueue.h" +#include "base/TMethodJob.h" +#include "mt/Thread.h" struct termios; -class NonBlockingStream +class StdinListen { public: - explicit NonBlockingStream(int fd = 0); - ~NonBlockingStream(); - - bool try_read_char(char &ch) const; + explicit StdinListen(IEventQueue* events); + ~StdinListen(); private: - int _fd; - termios * _p_ta_previous; - int _cntl_previous; + void stdinThread(void*); + + IEventQueue* m_events; + Thread* m_thread; + termios* _p_ta_previous; }; -#endif +#endif \ No newline at end of file