#include #include #include #include #include "log.h" #include "misc.h" #include "logcat_thread.h" #define EPOLL_MAX_EVENTS 10 static void mark_nonblock(int fd) { int flags = fcntl(fd, F_GETFL); if (flags < 0) { throw make_system_error("fcntl(fd, F_GETFL)"); } if (!(flags & O_NONBLOCK) && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { throw make_system_error("fcntl(fd, F_SETFL)"); } } LogcatThread::LogcatThread(bool* run_event_loop) { int fds[2]; struct epoll_event event = {.events = EPOLLIN | EPOLLET}; if (pipe(fds)) { std::system_error e = make_system_error("pipe() for stdout"); this->~LogcatThread(); throw e; } this->_stdout_read_fd = fds[0]; this->_stdout_write_fd = fds[1]; try { mark_nonblock(this->_stdout_read_fd); } catch (const std::exception& e) { this->~LogcatThread(); throw; } if (pipe(fds)) { std::system_error e = make_system_error("pipe() for stderr"); this->~LogcatThread(); throw e; } this->_stderr_read_fd = fds[0]; this->_stderr_write_fd = fds[1]; try { mark_nonblock(this->_stderr_read_fd); } catch (const std::exception& e) { this->~LogcatThread(); throw; } this->_epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (this->_epoll_fd == -1) { throw make_system_error("epoll_create1()"); } event.data.fd = this->_stdout_read_fd; if (epoll_ctl(this->_epoll_fd, EPOLL_CTL_ADD, this->_stdout_read_fd, &event)) { std::system_error e = make_system_error("epoll_ctl() for stdout"); this->~LogcatThread(); throw e; } event.data.fd = this->_stderr_read_fd; if (epoll_ctl(this->_epoll_fd, EPOLL_CTL_ADD, this->_stderr_read_fd, &event)) { std::system_error e = make_system_error("epoll_ctl() for stderr"); this->~LogcatThread(); throw e; } this->_thread = std::thread(&LogcatThread::_run, this, run_event_loop); } LogcatThread::~LogcatThread() { if (this->_epoll_fd != -1 && close(this->_epoll_fd)) { log(std::string("Failed to close epoll file descriptor: ") + make_system_error("close()").what()); } if (this->_stdout_read_fd != -1 && close(this->_stdout_read_fd)) { log(std::string("Failed to close stdout read pipe: ") + make_system_error("close()").what()); } if (this->_stdout_write_fd != -1 && close(this->_stdout_write_fd)) { log(std::string("Failed to close stdout write pipe: ") + make_system_error("close()").what()); } if (this->_stderr_read_fd != -1 && close(this->_stderr_read_fd)) { log(std::string("Failed to close stderr read pipe: ") + make_system_error("close()").what()); } if (this->_stderr_write_fd != -1 && close(this->_stderr_write_fd)) { log(std::string("Failed to close stderr write pipe: ") + make_system_error("close()").what()); } } void LogcatThread::join() { this->_thread.join(); } void LogcatThread::_run(bool* run_event_loop) { struct epoll_event events[EPOLL_MAX_EVENTS]; while (*run_event_loop) { printf("(boop)\n"); int ready_fds = epoll_wait(this->_epoll_fd, events, EPOLL_MAX_EVENTS, 1000); if (ready_fds == -1) { printf("%s\n", format_log(make_system_error("epoll_wait()").what()).c_str()); break; } for (int i=0; i < ready_fds; i++) { printf("ain't no way in hell do we get a ready fd (#%d) when we haven't set up anything\n", i); } } }