From b3c5a79aef7d34df24607e907164b5da13a198e9 Mon Sep 17 00:00:00 2001 From: jwestfall Date: Tue, 1 Jan 2019 13:55:16 -0800 Subject: [PATCH 1/3] Add StdinListen class and plumbing to use it --- src/lib/barrier/App.cpp | 15 ++++++++- src/lib/barrier/App.h | 3 ++ src/lib/base/StdinListen.cpp | 63 ++++++++++++++++++++++++++++++++++++ src/lib/base/StdinListen.h | 50 ++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 src/lib/base/StdinListen.cpp create mode 100644 src/lib/base/StdinListen.h 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/base/StdinListen.cpp b/src/lib/base/StdinListen.cpp new file mode 100644 index 00000000..3612319d --- /dev/null +++ b/src/lib/base/StdinListen.cpp @@ -0,0 +1,63 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2008 Debauchee Open Source Group + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if !defined(_WIN32) + +#include "base/StdinListen.h" +#include "../gui/src/ShutdownCh.h" + +#include // tcgetattr/tcsetattr, read +#include // tcgetattr/tcsetattr + +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(STDIN_FILENO, &ta); + _p_ta_previous = new termios(ta); + ta.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &ta); + + m_thread = new Thread(new TMethodJob( + this, &StdinListen::stdinThread)); +} + +StdinListen::~StdinListen() +{ + tcsetattr(STDIN_FILENO, TCSANOW, _p_ta_previous); + delete _p_ta_previous; +} + +void +StdinListen::stdinThread(void *) +{ + char ch; + + while (1) { + if (read(STDIN_FILENO, &ch, 1) == 1) { + if (ch == ShutdownCh) { + m_events->addEvent(Event(Event::kQuit)); + break; + } + } + } +} + +#endif // !defined(_WIN32) \ No newline at end of file diff --git a/src/lib/base/StdinListen.h b/src/lib/base/StdinListen.h new file mode 100644 index 00000000..8491ba59 --- /dev/null +++ b/src/lib/base/StdinListen.h @@ -0,0 +1,50 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2008 Debauchee Open Source Group + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#if defined(_WIN32) + +class StdinListen +{ +public: + void stdinThread(void*) {}; +}; + +#else + +#include "base/IEventQueue.h" +#include "base/TMethodJob.h" +#include "mt/Thread.h" + +struct termios; + +class StdinListen +{ +public: + explicit StdinListen(IEventQueue* events); + ~StdinListen(); + +private: + void stdinThread(void*); + + IEventQueue* m_events; + Thread* m_thread; + termios* _p_ta_previous; +}; + +#endif \ No newline at end of file From c67ad71c909f2eb48af28c9c4f3c6bc03e6aff41 Mon Sep 17 00:00:00 2001 From: jwestfall Date: Tue, 1 Jan 2019 14:01:11 -0800 Subject: [PATCH 2/3] Enable new StdinListen and disable old stdin reading code --- src/lib/barrier/ClientApp.cpp | 5 +++++ src/lib/barrier/ServerApp.cpp | 5 +++++ src/lib/base/EventQueue.cpp | 4 ++++ src/lib/base/EventQueue.h | 6 +++--- 4 files changed, 17 insertions(+), 3 deletions(-) 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 32966bbd..ed634803 100644 --- a/src/lib/barrier/ServerApp.cpp +++ b/src/lib/barrier/ServerApp.cpp @@ -721,6 +721,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..908ed439 100644 --- a/src/lib/base/EventQueue.cpp +++ b/src/lib/base/EventQueue.cpp @@ -201,12 +201,14 @@ 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) @@ -214,10 +216,12 @@ 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..a3980f2f 100644 --- a/src/lib/base/EventQueue.h +++ b/src/lib/base/EventQueue.h @@ -26,7 +26,7 @@ #include "base/Stopwatch.h" #include "common/stdmap.h" #include "common/stdset.h" -#include "base/NonBlockingStream.h" +//#include "base/NonBlockingStream.h" #include @@ -73,7 +73,7 @@ private: bool hasTimerExpired(Event& event); double getNextTimerTimeout() const; void addEventToBuffer(const Event& event); - bool parent_requests_shutdown() const; + //bool parent_requests_shutdown() const; private: class Timer { @@ -186,7 +186,7 @@ private: Mutex* m_readyMutex; CondVar* m_readyCondVar; std::queue m_pending; - NonBlockingStream m_parentStream; + //NonBlockingStream m_parentStream; }; #define EVENT_TYPE_ACCESSOR(type_) \ From 7c5bfcc5ae87c4c984a15261d3ea48b5fe4231b5 Mon Sep 17 00:00:00 2001 From: jwestfall Date: Tue, 1 Jan 2019 14:05:19 -0800 Subject: [PATCH 3/3] Remove old stdin reading code --- src/lib/base/EventQueue.cpp | 16 -------- src/lib/base/EventQueue.h | 3 -- src/lib/base/NonBlockingStream.cpp | 60 ------------------------------ src/lib/base/NonBlockingStream.h | 49 ------------------------ 4 files changed, 128 deletions(-) delete mode 100644 src/lib/base/NonBlockingStream.cpp delete mode 100644 src/lib/base/NonBlockingStream.h diff --git a/src/lib/base/EventQueue.cpp b/src/lib/base/EventQueue.cpp index 908ed439..bb5f07fc 100644 --- a/src/lib/base/EventQueue.cpp +++ b/src/lib/base/EventQueue.cpp @@ -201,27 +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 a3980f2f..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/NonBlockingStream.cpp deleted file mode 100644 index d44add15..00000000 --- a/src/lib/base/NonBlockingStream.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * barrier -- mouse and keyboard sharing utility - * Copyright (C) 2008 Debauchee Open Source Group - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#if !defined(_WIN32) - -#include "base/NonBlockingStream.h" - -#include // tcgetattr/tcsetattr, read -#include // tcgetattr/tcsetattr -#include -#include -#include - -NonBlockingStream::NonBlockingStream(int fd) : - _fd(fd) -{ - // 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); - _p_ta_previous = new termios(ta); - ta.c_lflag &= ~(ICANON | ECHO); - tcsetattr(fd, 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); -} - -NonBlockingStream::~NonBlockingStream() -{ - tcsetattr(_fd, TCSANOW, _p_ta_previous); - fcntl(_fd, F_SETFL, _cntl_previous); - delete _p_ta_previous; -} - -bool NonBlockingStream::try_read_char(char &ch) const -{ - int result = read(_fd, &ch, 1); - if (result == 1) - return true; - assert(result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)); - return false; -} - -#endif // !defined(_WIN32) diff --git a/src/lib/base/NonBlockingStream.h b/src/lib/base/NonBlockingStream.h deleted file mode 100644 index 4c27762a..00000000 --- a/src/lib/base/NonBlockingStream.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * barrier -- mouse and keyboard sharing utility - * Copyright (C) 2008 Debauchee Open Source Group - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#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 -{ -public: - bool try_read_char(char &ch) const { return false; }; -}; - -#else // non-windows platforms - -struct termios; - -class NonBlockingStream -{ -public: - explicit NonBlockingStream(int fd = 0); - ~NonBlockingStream(); - - bool try_read_char(char &ch) const; - -private: - int _fd; - termios * _p_ta_previous; - int _cntl_previous; -}; - -#endif