logmeow/logcat_thread.cpp

113 lines
3.5 KiB
C++

#include <fcntl.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <system_error>
#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);
}
}
}