FEXServer: Use a pipe to register new log clients instead of signaling across threads

This commit is contained in:
Tony Wasserka committed 2025-02-06 22:35:29 +01:00
1 parent 2bb37357c0
commit e36fb47d98
1 file changed
+56 -59
+56 -59
View File
@@ -12,12 +12,8 @@ void ClientMsgHandler(int FD, FEXServerClient::Logging::PacketMsg* const Msg, co
}
namespace Logger {
std::vector<struct pollfd> PollFDs {};
std::mutex IncomingPollFDsLock {};
std::vector<struct pollfd> IncomingPollFDs {};
int LogClientQueuePipe[2];
std::thread LogThread;
std::atomic<bool> ShouldShutdown {false};
std::atomic<int32_t> LoggerThreadTID {};
void HandleLogData(int Socket) {
std::vector<uint8_t> Data(1500);
@@ -58,71 +54,75 @@ void HandleLogData(int Socket) {
}
void LogThreadFunc() {
LoggerThreadTID = FHU::Syscalls::gettid();
std::vector<pollfd> PollFDs;
PollFDs.push_back(pollfd {.fd = LogClientQueuePipe[0], .events = POLLIN | POLLHUP, .revents = 0});
while (!ShouldShutdown) {
struct timespec ts {};
ts.tv_sec = 5;
{
std::unique_lock lk {IncomingPollFDsLock};
PollFDs.insert(PollFDs.end(), std::make_move_iterator(IncomingPollFDs.begin()), std::make_move_iterator(IncomingPollFDs.end()));
IncomingPollFDs.clear();
while (true) {
int Result = ppoll(PollFDs.data(), PollFDs.size(), nullptr, nullptr);
if (Result <= 0) {
continue;
}
if (PollFDs.size() == 0) {
pselect(0, nullptr, nullptr, nullptr, &ts, nullptr);
} else {
int Result = ppoll(&PollFDs.at(0), PollFDs.size(), &ts, nullptr);
if (Result > 0) {
// Walk the FDs and see if we got any results
for (auto it = PollFDs.begin(); it != PollFDs.end();) {
bool Erase {};
if (it->revents != 0) {
if (it->revents & POLLIN) {
// Data from the socket
HandleLogData(it->fd);
} else if (it->revents & (POLLHUP | POLLERR | POLLNVAL | POLLRDHUP)) {
// Error or hangup, close the socket and erase it from our list
Erase = true;
close(it->fd);
}
it->revents = 0;
--Result;
}
// Process events for client pipe
if (PollFDs[0].revents) {
--Result;
if (Erase) {
it = PollFDs.erase(it);
} else {
++it;
}
auto [PipeFD, _, revents] = PollFDs[0];
PollFDs[0].revents = 0;
if (Result == 0) {
// Early break if we've consumed all the results
break;
}
}
if (revents & POLLIN) {
int ReceivedFD;
read(PipeFD, &ReceivedFD, sizeof(ReceivedFD));
PollFDs.push_back(pollfd {
.fd = ReceivedFD,
.events = POLLIN,
.revents = 0,
});
}
if (revents & POLLHUP) {
close(PipeFD);
return;
}
}
// Process events for log FDs
for (auto it = PollFDs.begin() + 1; Result && it != PollFDs.end();) {
if (it->revents == 0) {
++it;
continue;
}
--Result;
bool Erase {};
if (it->revents & POLLIN) {
// Data from the socket
HandleLogData(it->fd);
} else if (it->revents & (POLLHUP | POLLERR | POLLNVAL | POLLRDHUP)) {
// Error or hangup, close the socket and erase it from our list
Erase = true;
close(it->fd);
}
it->revents = 0;
if (Erase) {
it = PollFDs.erase(it);
} else {
++it;
}
}
}
}
void StartLogThread() {
pipe2(LogClientQueuePipe, 0);
LogThread = std::thread(LogThreadFunc);
}
void AppendLogFD(int FD) {
{
std::unique_lock lk {IncomingPollFDsLock};
IncomingPollFDs.emplace_back(pollfd {
.fd = FD,
.events = POLLIN,
.revents = 0,
});
}
// Wake up the thread immediately
FHU::Syscalls::tgkill(::getpid(), LoggerThreadTID, SIGUSR1);
write(LogClientQueuePipe[1], &FD, sizeof(FD));
}
bool LogThreadRunning() {
@@ -130,10 +130,7 @@ bool LogThreadRunning() {
}
void Shutdown() {
ShouldShutdown = true;
// Wake up the thread immediately
FHU::Syscalls::tgkill(::getpid(), LoggerThreadTID, SIGUSR1);
close(LogClientQueuePipe[1]);
if (LogThread.joinable()) {
LogThread.join();