129 lines
4.0 KiB
C++
129 lines
4.0 KiB
C++
#include <cstring>
|
|
#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_system_error("fcntl(fd, F_GETFL)");
|
|
}
|
|
if (!(flags & O_NONBLOCK) && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
|
throw_system_error("fcntl(fd, F_SETFL)");
|
|
}
|
|
}
|
|
|
|
|
|
LogcatThread::LogcatThread() {
|
|
int fds[2];
|
|
struct epoll_event event = {.events = EPOLLIN | EPOLLET};
|
|
|
|
if (pipe(fds)) {
|
|
int errsv = errno;
|
|
this->~LogcatThread();
|
|
throw_system_error(errsv, "pipe() for stdout");
|
|
}
|
|
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)) {
|
|
int errsv = errno;
|
|
this->~LogcatThread();
|
|
throw_system_error(errsv, "pipe() for stderr");
|
|
}
|
|
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) {
|
|
int errsv = errno;
|
|
this->~LogcatThread();
|
|
throw_system_error(errsv, "epoll_create1()");
|
|
}
|
|
event.data.fd = this->_stdout_read_fd;
|
|
if (epoll_ctl(this->_epoll_fd, EPOLL_CTL_ADD, this->_stdout_read_fd, &event)) {
|
|
int errsv = errno;
|
|
this->~LogcatThread();
|
|
throw_system_error(errsv, "epoll_ctl() for stdout");
|
|
}
|
|
event.data.fd = this->_stderr_read_fd;
|
|
if (epoll_ctl(this->_epoll_fd, EPOLL_CTL_ADD, this->_stderr_read_fd, &event)) {
|
|
int errsv = errno;
|
|
this->~LogcatThread();
|
|
throw_system_error(errsv, "epoll_ctl() for stderr");
|
|
}
|
|
|
|
this->_thread = std::thread(&LogcatThread::_run, this, this->_stop_source.get_token());
|
|
}
|
|
|
|
LogcatThread::~LogcatThread() {
|
|
if (this->_epoll_fd != -1 && close(this->_epoll_fd)) {
|
|
log(std::string("Failed to close epoll file descriptor: close(): ") + strerror(errno));
|
|
}
|
|
if (this->_stdout_read_fd != -1 && close(this->_stdout_read_fd)) {
|
|
log(std::string("Failed to close stdout read pipe: close(): ") + strerror(errno));
|
|
}
|
|
if (this->_stdout_write_fd != -1 && close(this->_stdout_write_fd)) {
|
|
log(std::string("Failed to close stdout write pipe: close(): ") + strerror(errno));
|
|
}
|
|
if (this->_stderr_read_fd != -1 && close(this->_stderr_read_fd)) {
|
|
log(std::string("Failed to close stderr read pipe: close(): ") + strerror(errno));
|
|
}
|
|
if (this->_stderr_write_fd != -1 && close(this->_stderr_write_fd)) {
|
|
log(std::string("Failed to close stderr write pipe: close(): ") + strerror(errno));
|
|
}
|
|
}
|
|
|
|
void LogcatThread::request_stop() {
|
|
this->_stop_source.request_stop();
|
|
}
|
|
|
|
void LogcatThread::join() {
|
|
this->_thread.join();
|
|
}
|
|
|
|
void LogcatThread::_run(std::stop_token stoken) {
|
|
struct epoll_event events[EPOLL_MAX_EVENTS];
|
|
|
|
while (!stoken.stop_requested()) {
|
|
printf("(boop)\n");
|
|
#ifndef NDEBUG
|
|
if (this->debug_log_request.test()) {
|
|
this->atomic_ring_buffer.put_and_increment_write(format_log("A log entry from the logcat thread :D"));
|
|
this->debug_log_request.clear();
|
|
}
|
|
#endif
|
|
|
|
int ready_fds = epoll_wait(this->_epoll_fd, events, EPOLL_MAX_EVENTS, 1000);
|
|
if (ready_fds == -1) {
|
|
std::string log_entry = format_log(std::string("epoll_wait(): ") + strerror(errno));
|
|
printf("%s\n", log_entry.c_str());
|
|
this->atomic_ring_buffer.put_and_increment_write(std::move(log_entry));
|
|
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);
|
|
}
|
|
}
|
|
}
|