mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
FEXServer: Add support for querying code maps
Managing code maps in FEXServer rather than in FEXInterpreter makes it easier to handle multiple concurrent processes sharing code caches for the main executable and libraries.
This commit is contained in:
1 parent
b34b711161
commit
b6cff01abb
3 files changed
+104
-1
No files matched your search
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "Common/AsyncNet.h"
|
||||
#include "Common/Config.h"
|
||||
#include "FDUtils.h"
|
||||
#include "Common/FEXServerClient.h"
|
||||
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
@@ -375,6 +376,38 @@ int RequestPIDFD(int ServerSocket) {
|
||||
return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_PID_FD);
|
||||
}
|
||||
|
||||
int RequestCodeMapFD(int ServerSocket, int ProgramFD, bool HasMultiblock) {
|
||||
fasio::tcp_socket Socket {ServerSocket};
|
||||
FEXServerRequestPacket Req {
|
||||
.Header {
|
||||
.Type = HasMultiblock ? PacketType::TYPE_QUERY_CODE_MAP : PacketType::TYPE_QUERY_CODE_MAP_NO_MULTIBLOCK,
|
||||
},
|
||||
};
|
||||
|
||||
// Send request
|
||||
fasio::error ec;
|
||||
{
|
||||
fasio::mutable_buffer WriteBuffer {std::as_writable_bytes(std::span {&Req, 1})};
|
||||
WriteBuffer.FD = &ProgramFD;
|
||||
write(Socket, WriteBuffer, ec);
|
||||
if (ec != fasio::error::success) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for success response and log FD
|
||||
FEXServerResultPacket Res {};
|
||||
fasio::mutable_buffer ResBuffer {std::as_writable_bytes(std::span {&Res, 1})};
|
||||
int NewFD = -1;
|
||||
ResBuffer.FD = &NewFD;
|
||||
read(Socket, ResBuffer, ec);
|
||||
if (ec != fasio::error::success || Res.Header.Type != PacketType::TYPE_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return NewFD;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,8 @@ enum class PacketType {
|
||||
TYPE_GET_LOG_FD,
|
||||
TYPE_GET_ROOTFS_PATH,
|
||||
TYPE_GET_PID_FD,
|
||||
TYPE_QUERY_CODE_MAP,
|
||||
TYPE_QUERY_CODE_MAP_NO_MULTIBLOCK,
|
||||
|
||||
// Result only
|
||||
TYPE_SUCCESS,
|
||||
@@ -113,6 +115,16 @@ fextl::string RequestRootFSPath(int ServerSocket);
|
||||
*/
|
||||
int RequestPIDFD(int ServerSocket);
|
||||
|
||||
/**
|
||||
* @brief Request FEXServer to create a new code map for disk cache population
|
||||
*
|
||||
* @param ServerSocket - Socket to the server
|
||||
* @param ProgramFD - FD for program binary
|
||||
*
|
||||
* @return FD to write code map to
|
||||
*/
|
||||
int RequestCodeMapFD(int ServerSocket, int ProgramFD, bool HasMultiblock);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
#include "SquashFS.h"
|
||||
|
||||
#include <Common/AsyncNet.h>
|
||||
#include <Common/Config.h>
|
||||
#include <Common/FDUtils.h>
|
||||
#include <Common/FEXServerClient.h>
|
||||
|
||||
#include <FEXCore/Core/CodeCache.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include <atomic>
|
||||
@@ -19,6 +24,8 @@
|
||||
#include <sys/un.h>
|
||||
#include <vector>
|
||||
|
||||
#include <xxhash.h>
|
||||
|
||||
namespace ProcessPipe {
|
||||
constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
int ServerLockFD {-1};
|
||||
@@ -34,6 +41,8 @@ constexpr size_t static MAX_FD_DISTANCE = 32;
|
||||
rlimit MaxFDs {};
|
||||
std::atomic<size_t> NumFilesOpened {};
|
||||
|
||||
static std::string CodeMapDirectory;
|
||||
|
||||
size_t GetNumFilesOpen() {
|
||||
// Walk /proc/self/fd/ to see how many open files we currently have
|
||||
const std::filesystem::path self {"/proc/self/fd/"};
|
||||
@@ -267,7 +276,8 @@ void HandleSocketData(fasio::tcp_socket& Socket) {
|
||||
// Get the current number of FDs of the process before we start handling sockets.
|
||||
GetMaxFDs();
|
||||
|
||||
fasio::mutable_buffer buffer = {std::as_writable_bytes(std::span(Data))};
|
||||
int inFD = -1;
|
||||
fasio::mutable_buffer buffer = {std::as_writable_bytes(std::span(Data)), nullptr, &inFD};
|
||||
|
||||
{
|
||||
fasio::error ec;
|
||||
@@ -369,6 +379,47 @@ void HandleSocketData(fasio::tcp_socket& Socket) {
|
||||
buffer += sizeof(FEXServerClient::FEXServerRequestPacket::Header);
|
||||
break;
|
||||
}
|
||||
|
||||
case FEXServerClient::PacketType::TYPE_QUERY_CODE_MAP:
|
||||
case FEXServerClient::PacketType::TYPE_QUERY_CODE_MAP_NO_MULTIBLOCK: {
|
||||
char Tmp[PATH_MAX];
|
||||
int TmpLen = FEX::get_fdpath(inFD, Tmp);
|
||||
assert(TmpLen != -1);
|
||||
std::filesystem::path BinaryPath = std::string_view(Tmp, TmpLen);
|
||||
// TODO: Move to common code
|
||||
const auto filename_hash = XXH3_64bits(Tmp, TmpLen);
|
||||
const bool HasMultiblock = (Req->Header.Type == FEXServerClient::PacketType::TYPE_QUERY_CODE_MAP);
|
||||
|
||||
FEXServerClient::FEXServerResultPacket Res {
|
||||
.Header {
|
||||
.Type = FEXServerClient::PacketType::TYPE_SUCCESS,
|
||||
},
|
||||
};
|
||||
|
||||
// Find first code map that doesn't exist yet
|
||||
int Index = 0;
|
||||
std::string Filename;
|
||||
do {
|
||||
Filename = fmt::format("{}/{}.{}.bin", CodeMapDirectory,
|
||||
FEXCore::CodeMap::GetBaseFilename(
|
||||
FEXCore::ExecutableFileInfo {nullptr, filename_hash, (fextl::string)BinaryPath.string()}, !HasMultiblock),
|
||||
Index++);
|
||||
} while (std::filesystem::exists(Filename));
|
||||
|
||||
std::filesystem::create_directories(CodeMapDirectory);
|
||||
auto CodeMapFD = open(Filename.c_str(), O_CREAT | O_CLOEXEC | O_WRONLY, 0644);
|
||||
|
||||
fasio::mutable_buffer Data = {.Data = std::as_writable_bytes(std::span(&Res, 1)),
|
||||
.FD = (CodeMapFD != -1 ? std::optional {&CodeMapFD} : std::nullopt)};
|
||||
fasio::error ec;
|
||||
write(Socket, Data, ec);
|
||||
buffer += sizeof(FEXServerClient::FEXServerRequestPacket::Header);
|
||||
close(inFD);
|
||||
inFD = -1;
|
||||
close(CodeMapFD);
|
||||
break;
|
||||
}
|
||||
|
||||
// Invalid
|
||||
case FEXServerClient::PacketType::TYPE_ERROR:
|
||||
default:
|
||||
@@ -378,6 +429,11 @@ void HandleSocketData(fasio::tcp_socket& Socket) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (inFD != -1) {
|
||||
LogMan::Msg::EFmt("Received unused FD argument");
|
||||
close(inFD);
|
||||
}
|
||||
}
|
||||
|
||||
void CloseConnections() {
|
||||
@@ -413,6 +469,8 @@ void WaitForRequests() {
|
||||
void SetConfiguration(bool Foreground, uint32_t PersistentTimeout) {
|
||||
ProcessPipe::Foreground = Foreground;
|
||||
ProcessPipe::RequestTimeout = PersistentTimeout;
|
||||
|
||||
CodeMapDirectory = FEX::Config::GetCacheDirectory() + "codemap";
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
||||
Reference in new issue
Block a user