do not multithread

This commit is contained in:
PancakeTAS 2025-07-19 13:08:11 +02:00
parent 8b63447d41
commit c1413a3ed9
No known key found for this signature in database
5 changed files with 30 additions and 134 deletions

View file

@ -2,6 +2,8 @@
#include <vulkan/vulkan_core.h>
#include <filesystem>
#include <chrono>
#include <cstddef>
#include <vector>
#include <atomic>
@ -33,24 +35,17 @@ namespace Config {
/// Experimental flag for limiting the framerate of DXVK games.
uint32_t e_fps_limit;
/// Atomic property to check if the configuration is valid or outdated.
std::shared_ptr<std::atomic_bool> valid;
/// Path to the configuration file.
std::filesystem::path config_file;
/// File timestamp of the configuration file
std::chrono::time_point<std::chrono::file_clock> timestamp;
};
/// Active configuration. Must be set in main.cpp.
extern Configuration activeConf;
///
/// Load the config file and create a file watcher.
///
/// @param file The path to the configuration file.
///
/// @throws std::runtime_error if an error occurs while loading the configuration file.
///
void loadAndWatchConfig(const std::string& file);
///
/// Reread the configuration file while preserving the old configuration
/// Read the configuration file while preserving the previous configuration
/// in case of an error.
///
/// @param file The path to the configuration file.

View file

@ -4,14 +4,9 @@
#include "config/default_conf.hpp"
#include <vulkan/vulkan_core.h>
#include <linux/limits.h>
#include <sys/inotify.h>
#include <sys/poll.h>
#include <toml11/find.hpp>
#include <toml11/parser.hpp>
#include <toml.hpp>
#include <unistd.h>
#include <poll.h>
#include <unordered_map>
#include <filesystem>
@ -21,19 +16,11 @@
#include <iostream>
#include <optional>
#include <fstream>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <utility>
#include <cstring>
#include <vector>
#include <chrono>
#include <thread>
#include <cerrno>
#include <atomic>
#include <memory>
#include <string>
#include <array>
using namespace Config;
@ -44,103 +31,6 @@ namespace {
Configuration Config::activeConf{};
namespace {
[[noreturn]] void thread(
const std::string& file,
const std::shared_ptr<std::atomic_bool>& valid) {
const int fd = inotify_init();
if (fd < 0)
throw std::runtime_error("Failed to initialize inotify:\n"
"- " + std::string(strerror(errno)));
const std::string parent = std::filesystem::path(file).parent_path().string();
const int wd = inotify_add_watch(fd, parent.c_str(),
IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE_SELF);
if (wd < 0) {
close(fd);
throw std::runtime_error("Failed to add inotify watch for " + parent + ":\n"
"- " + std::string(strerror(errno)));
}
// watch for changes
std::optional<std::chrono::steady_clock::time_point> discard_until;
const std::string filename = std::filesystem::path(file).filename().string();
std::array<char, (sizeof(inotify_event) + NAME_MAX + 1) * 20> buffer{};
while (true) {
// poll fd
struct pollfd pfd{};
pfd.fd = fd;
pfd.events = POLLIN;
const int pollRes = poll(&pfd, 1, 100);
if (pollRes < 0 && errno != EINTR) {
inotify_rm_watch(fd, wd);
close(fd);
throw std::runtime_error("Error polling inotify events:\n"
"- " + std::string(strerror(errno)));
}
// read fd if there are events
const ssize_t len = pollRes == 0 ? 0 : read(fd, buffer.data(), buffer.size());
if (len <= 0 && errno != EINTR && pollRes > 0) {
inotify_rm_watch(fd, wd);
close(fd);
throw std::runtime_error("Error reading inotify events:\n"
"- " + std::string(strerror(errno)));
}
size_t i{};
while (std::cmp_less(i, len)) {
auto* event = reinterpret_cast<inotify_event*>(&buffer.at(i));
i += sizeof(inotify_event) + event->len;
if (event->len <= 0 || event->mask & IN_IGNORED)
continue;
const std::string name(reinterpret_cast<char*>(event->name));
if (name != filename)
continue;
// stall a bit, then mark as invalid
discard_until.emplace(std::chrono::steady_clock::now()
+ std::chrono::milliseconds(500));
}
auto now = std::chrono::steady_clock::now();
if (discard_until.has_value() && now > *discard_until) {
discard_until.reset();
// mark config as invalid
valid->store(false, std::memory_order_release);
// and wait until it has been marked as valid again
while (!valid->load(std::memory_order_acquire))
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
}
}
void Config::loadAndWatchConfig(const std::string& file) {
globalConf.valid = std::make_shared<std::atomic_bool>(true);
updateConfig(file);
// prepare config watcher
if (std::getenv("LSFG_NO_HOT_RELOAD"))
return;
std::thread([file = file, valid = globalConf.valid]() {
try {
thread(file, valid);
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: Error in config watcher thread:\n";
std::cerr << "- " << e.what() << '\n';
}
}).detach();
}
namespace {
/// Turn a string into a VkPresentModeKHR enum value.
VkPresentModeKHR into_present(const std::string& mode) {
@ -195,7 +85,6 @@ namespace {
}
void Config::updateConfig(const std::string& file) {
globalConf.valid->store(true, std::memory_order_relaxed);
if (!std::filesystem::exists(file)) {
std::cerr << "lsfg-vk: Placing default configuration file at " << file << '\n';
const auto parent = std::filesystem::path(file).parent_path();
@ -227,7 +116,8 @@ void Config::updateConfig(const std::string& file) {
const toml::value globalTable = toml::find_or_default<toml::table>(toml, "global");
const Configuration global{
.dll = toml::find_or(globalTable, "dll", std::string()),
.valid = globalConf.valid // use the same validity flag
.config_file = file,
.timestamp = std::filesystem::last_write_time(file)
};
// validate global configuration
@ -256,7 +146,8 @@ void Config::updateConfig(const std::string& file) {
.hdr = toml::find_or(gameTable, "hdr_mode", false),
.e_present = into_present(toml::find_or(gameTable, "experimental_present_mode", "")),
.e_fps_limit = toml::find_or(gameTable, "experimental_fps_limit", 0U),
.valid = global.valid // only need a single validity flag
.config_file = file,
.timestamp = global.timestamp
};
// validate the configuration
@ -279,8 +170,7 @@ Configuration Config::getConfig(const std::pair<std::string, std::string>& name)
.enable = true,
.multiplier = 2,
.flowScale = 1.0F,
.e_present = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR,
.valid = std::make_shared<std::atomic_bool>(true)
.e_present = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR
};
const char* dll = std::getenv("LSFG_DLL_PATH");

View file

@ -11,14 +11,16 @@
#include <lsfg_3_1.hpp>
#include <lsfg_3_1p.hpp>
#include <filesystem>
#include <exception>
#include <iostream>
#include <cstdint>
#include <cstdlib>
#include <atomic>
#include <string>
#include <memory>
#include <vector>
#include <chrono>
#include <memory>
#include <string>
#include <thread>
#include <array>
LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain,
@ -27,8 +29,13 @@ LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain,
extent(extent) {
// get updated configuration
auto& conf = Config::activeConf;
if (!conf.valid->load(std::memory_order_relaxed)) {
if (!conf.config_file.empty()
&& (
!std::filesystem::exists(conf.config_file)
|| conf.timestamp != std::filesystem::last_write_time(conf.config_file)
)) {
std::cerr << "lsfg-vk: Rereading configuration, as it is no longer valid.\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// reread configuration
const std::string file = Utils::getConfigFile();

View file

@ -8,13 +8,13 @@
#include <vulkan/vulkan_core.h>
#include <unordered_map>
#include <filesystem>
#include <stdexcept>
#include <algorithm>
#include <exception>
#include <iostream>
#include <cstdint>
#include <cstdlib>
#include <atomic>
#include <string>
#include <vector>
@ -261,7 +261,11 @@ namespace {
try {
// ensure config is valid
auto& conf = Config::activeConf;
if (!conf.valid->load(std::memory_order_relaxed)) {
if (!conf.config_file.empty()
&& (
!std::filesystem::exists(conf.config_file)
|| conf.timestamp != std::filesystem::last_write_time(conf.config_file)
)) {
Layer::ovkQueuePresentKHR(queue, pPresentInfo);
return VK_ERROR_OUT_OF_DATE_KHR;
}

View file

@ -22,7 +22,7 @@ namespace {
// read configuration
const std::string file = Utils::getConfigFile();
try {
Config::loadAndWatchConfig(file);
Config::updateConfig(file);
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: An error occured while trying to parse the configuration, IGNORING:\n";
std::cerr << "- " << e.what() << '\n';