diff --git a/CMakeLists.txt b/CMakeLists.txt index acdb181..ccd1a9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ if (LINUX) find_package(Fontconfig) list(APPEND LIBS ${LINUX_GL_LIBS} -ldl) list(APPEND IMGUI_LIBS ${LINUX_GL_LIBS} -ldl) + list(APPEND FLAGS -DUSE_EPOLL) if (Fontconfig_FOUND) list(APPEND FLAGS -DUSE_FONTCONFIG) list(APPEND LIBS Fontconfig::Fontconfig) diff --git a/logcat_thread.cpp b/logcat_thread.cpp index d7a0812..ed6466b 100644 --- a/logcat_thread.cpp +++ b/logcat_thread.cpp @@ -3,8 +3,12 @@ #include #include #include -#include #include +#ifdef USE_EPOLL + #include +#else + #include +#endif #include "log.h" #include "misc.h" @@ -77,7 +81,6 @@ static inline void handle_fd(int fd, char* buf, size_t* used, LogcatThread::LogcatThread(const std::string* logcat_command) : _logcat_command(logcat_command) { int fds[2]; - struct epoll_event event = {.events = EPOLLIN | EPOLLET}; if (pipe(fds)) { int errsv = errno; @@ -107,6 +110,8 @@ LogcatThread::LogcatThread(const std::string* logcat_command) : _logcat_command( throw; } +#ifdef USE_EPOLL + struct epoll_event event = {.events = EPOLLIN | EPOLLET}; this->_epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (this->_epoll_fd == -1) { int errsv = errno; @@ -125,14 +130,17 @@ LogcatThread::LogcatThread(const std::string* logcat_command) : _logcat_command( this->~LogcatThread(); throw_system_error(errsv, "epoll_ctl() for stderr"); } +#endif this->_thread = std::thread(&LogcatThread::_run, this, this->_stop_source.get_token()); } LogcatThread::~LogcatThread() { +#ifdef USE_EPOLL if (this->_epoll_fd != -1 && close(this->_epoll_fd)) { log(std::string("Failed to close epoll file descriptor: close(): ") + strerror(errno)); } +#endif if (this->_stdout_read_fd != -1 && close(this->_stdout_read_fd)) { log(std::string("Failed to close stdout read pipe: close(): ") + strerror(errno)); } @@ -201,27 +209,68 @@ void LogcatThread::_handle_line(char* buf, size_t length, bool is_stdout) { this->_try_log(std::string("Cannot parse logcat stdout: ") + std::string(buf, length)); } -void LogcatThread::_run_epoll_round() { - struct epoll_event events[EPOLL_MAX_EVENTS]; - - int ready_fds = epoll_wait(this->_epoll_fd, events, EPOLL_MAX_EVENTS, 1000); - if (ready_fds == -1) { - int errsv = errno; // just in case if std::string overrides it - this->_try_log(std::string("epoll_wait(): ") + strerror(errsv)); - return; - } - - for (int i=0; i < ready_fds; i++) { - const bool is_stdout = events[i].data.fd == this->_stdout_read_fd; +void LogcatThread::_run_read_round() { + auto handle_ready_fd = [&](int fd) { + const bool is_stdout = fd == this->_stdout_read_fd; char* buf = is_stdout ? this->_stdout_buf : this->_stderr_buf; size_t* used = is_stdout ? &this->_stdout_buf_used : &this->_stderr_buf_used; try { - handle_fd(events[i].data.fd, buf, used, &LogcatThread::_handle_line, this, is_stdout); + handle_fd(fd, buf, used, &LogcatThread::_handle_line, this, is_stdout); } catch (const std::exception& e) { this->_try_log(std::string("Failed to handle std") + (is_stdout ? "out: " : "err: ") + e.what()); } + }; + +#ifdef USE_EPOLL + struct epoll_event events[EPOLL_MAX_EVENTS]; + + int ready_fds = epoll_wait(this->_epoll_fd, events, EPOLL_MAX_EVENTS, 1000); + if (ready_fds == -1) { + try { + throw_system_error("epoll_wait()"); + } catch (const std::exception& e) { + this->_try_log(e.what()); + } + return; } + + for (int i=0; i < ready_fds; i++) { + handle_ready_fd(events[i].data.fd); + } +#else + struct pollfd fds[2] = { + { + .fd = this->_stdout_read_fd, + .events = POLLIN | POLLPRI, + }, + { + .fd = this->_stderr_read_fd, + .events = POLLIN | POLLPRI, + }, + }; + + int ready_fds = poll(fds, 2, 1000); + if (ready_fds < 0) { + try { + throw_system_error("poll()"); + } catch (const std::exception& e) { + this->_try_log(e.what()); + } + return; + } else if (ready_fds == 0) { + return; + } + + if (fds[0].events & POLLIN || fds[0].events & POLLPRI) { + handle_ready_fd(fds[0].fd); + } + // ignore errors 'cause we'll keep the pipes open until thread termination + if (fds[1].events & POLLIN || fds[1].events & POLLPRI) { + handle_ready_fd(fds[1].fd); + } + // ignore errors 'cause we'll keep the pipes open until thread termination +#endif } void LogcatThread::_try_reap(bool has_request) { @@ -360,7 +409,7 @@ void LogcatThread::_run(std::stop_token stoken) { } #endif - this->_run_epoll_round(); + this->_run_read_round(); if (stoken.stop_requested() && this->_logcat_pid != -1) { this->_run_process_round(LogcatProcessRequest::Stop); diff --git a/logcat_thread.h b/logcat_thread.h index 0059f06..85ad304 100644 --- a/logcat_thread.h +++ b/logcat_thread.h @@ -38,14 +38,16 @@ private: void _try_log(std::string message); void _handle_line(char* buf, size_t length, bool is_stdout); void _run(std::stop_token stoken); - void _run_epoll_round(); + void _run_read_round(); void _try_reap(bool stop_requested); bool _handle_stop_request(); bool _handle_start_request(); bool _run_process_round(LogcatProcessRequest request); +#ifdef USE_EPOLL int _epoll_fd = -1; +#endif int _stdout_read_fd = -1; int _stdout_write_fd = -1; int _stderr_read_fd = -1;