Use poll if epoll is not available

This commit is contained in:
blankie 2023-02-21 15:09:45 +07:00
parent c3a277e232
commit 381e0d075a
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
3 changed files with 69 additions and 17 deletions

View File

@ -67,6 +67,7 @@ if (LINUX)
find_package(Fontconfig) find_package(Fontconfig)
list(APPEND LIBS ${LINUX_GL_LIBS} -ldl) list(APPEND LIBS ${LINUX_GL_LIBS} -ldl)
list(APPEND IMGUI_LIBS ${LINUX_GL_LIBS} -ldl) list(APPEND IMGUI_LIBS ${LINUX_GL_LIBS} -ldl)
list(APPEND FLAGS -DUSE_EPOLL)
if (Fontconfig_FOUND) if (Fontconfig_FOUND)
list(APPEND FLAGS -DUSE_FONTCONFIG) list(APPEND FLAGS -DUSE_FONTCONFIG)
list(APPEND LIBS Fontconfig::Fontconfig) list(APPEND LIBS Fontconfig::Fontconfig)

View File

@ -3,8 +3,12 @@
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/epoll.h>
#include <system_error> #include <system_error>
#ifdef USE_EPOLL
#include <sys/epoll.h>
#else
#include <poll.h>
#endif
#include "log.h" #include "log.h"
#include "misc.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) { LogcatThread::LogcatThread(const std::string* logcat_command) : _logcat_command(logcat_command) {
int fds[2]; int fds[2];
struct epoll_event event = {.events = EPOLLIN | EPOLLET};
if (pipe(fds)) { if (pipe(fds)) {
int errsv = errno; int errsv = errno;
@ -107,6 +110,8 @@ LogcatThread::LogcatThread(const std::string* logcat_command) : _logcat_command(
throw; throw;
} }
#ifdef USE_EPOLL
struct epoll_event event = {.events = EPOLLIN | EPOLLET};
this->_epoll_fd = epoll_create1(EPOLL_CLOEXEC); this->_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (this->_epoll_fd == -1) { if (this->_epoll_fd == -1) {
int errsv = errno; int errsv = errno;
@ -125,14 +130,17 @@ LogcatThread::LogcatThread(const std::string* logcat_command) : _logcat_command(
this->~LogcatThread(); this->~LogcatThread();
throw_system_error(errsv, "epoll_ctl() for stderr"); throw_system_error(errsv, "epoll_ctl() for stderr");
} }
#endif
this->_thread = std::thread(&LogcatThread::_run, this, this->_stop_source.get_token()); this->_thread = std::thread(&LogcatThread::_run, this, this->_stop_source.get_token());
} }
LogcatThread::~LogcatThread() { LogcatThread::~LogcatThread() {
#ifdef USE_EPOLL
if (this->_epoll_fd != -1 && close(this->_epoll_fd)) { if (this->_epoll_fd != -1 && close(this->_epoll_fd)) {
log(std::string("Failed to close epoll file descriptor: close(): ") + strerror(errno)); log(std::string("Failed to close epoll file descriptor: close(): ") + strerror(errno));
} }
#endif
if (this->_stdout_read_fd != -1 && close(this->_stdout_read_fd)) { if (this->_stdout_read_fd != -1 && close(this->_stdout_read_fd)) {
log(std::string("Failed to close stdout read pipe: close(): ") + strerror(errno)); 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)); this->_try_log(std::string("Cannot parse logcat stdout: ") + std::string(buf, length));
} }
void LogcatThread::_run_epoll_round() { void LogcatThread::_run_read_round() {
struct epoll_event events[EPOLL_MAX_EVENTS]; auto handle_ready_fd = [&](int fd) {
const bool is_stdout = fd == this->_stdout_read_fd;
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;
char* buf = is_stdout ? this->_stdout_buf : this->_stderr_buf; char* buf = is_stdout ? this->_stdout_buf : this->_stderr_buf;
size_t* used = is_stdout ? &this->_stdout_buf_used : &this->_stderr_buf_used; size_t* used = is_stdout ? &this->_stdout_buf_used : &this->_stderr_buf_used;
try { 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) { } catch (const std::exception& e) {
this->_try_log(std::string("Failed to handle std") + (is_stdout ? "out: " : "err: ") + e.what()); 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) { void LogcatThread::_try_reap(bool has_request) {
@ -360,7 +409,7 @@ void LogcatThread::_run(std::stop_token stoken) {
} }
#endif #endif
this->_run_epoll_round(); this->_run_read_round();
if (stoken.stop_requested() && this->_logcat_pid != -1) { if (stoken.stop_requested() && this->_logcat_pid != -1) {
this->_run_process_round(LogcatProcessRequest::Stop); this->_run_process_round(LogcatProcessRequest::Stop);

View File

@ -38,14 +38,16 @@ private:
void _try_log(std::string message); void _try_log(std::string message);
void _handle_line(char* buf, size_t length, bool is_stdout); void _handle_line(char* buf, size_t length, bool is_stdout);
void _run(std::stop_token stoken); void _run(std::stop_token stoken);
void _run_epoll_round(); void _run_read_round();
void _try_reap(bool stop_requested); void _try_reap(bool stop_requested);
bool _handle_stop_request(); bool _handle_stop_request();
bool _handle_start_request(); bool _handle_start_request();
bool _run_process_round(LogcatProcessRequest request); bool _run_process_round(LogcatProcessRequest request);
#ifdef USE_EPOLL
int _epoll_fd = -1; int _epoll_fd = -1;
#endif
int _stdout_read_fd = -1; int _stdout_read_fd = -1;
int _stdout_write_fd = -1; int _stdout_write_fd = -1;
int _stderr_read_fd = -1; int _stderr_read_fd = -1;