Make system config thread-safe (almost)

This commit is contained in:
Nekotekina 2020-01-20 19:08:57 +03:00
parent 0147bc2c72
commit 0f87c6c7c3
4 changed files with 53 additions and 39 deletions

View file

@ -326,7 +326,7 @@ void cfg::_bool::from_default()
void cfg::string::from_default()
{
m_value = def;
m_value = m_value.make(def);
}
void cfg::set_entry::from_default()

View file

@ -3,6 +3,8 @@
#include "Utilities/types.h"
#include "Utilities/StrFmt.h"
#include "Utilities/Log.h"
#include "util/atomic.hpp"
#include "util/shared_cptr.hpp"
#include <utility>
#include <string>
@ -121,10 +123,10 @@ namespace cfg
class _bool final : public _base
{
bool m_value;
atomic_t<bool> m_value;
public:
bool def;
const bool def;
_bool(node* owner, const std::string& name, bool def = false, bool dynamic = false)
: _base(type::_bool, owner, name, dynamic)
@ -138,7 +140,7 @@ namespace cfg
return m_value;
}
const bool& get() const
bool get() const
{
return m_value;
}
@ -172,7 +174,7 @@ namespace cfg
template <typename T>
class _enum final : public _base
{
T m_value;
atomic_t<T> m_value;
public:
const T def;
@ -189,7 +191,7 @@ namespace cfg
return m_value;
}
const T& get() const
T get() const
{
return m_value;
}
@ -202,7 +204,7 @@ namespace cfg
std::string to_string() const override
{
std::string result;
fmt_class_string<T>::format(result, fmt_unveil<T>::get(m_value));
fmt_class_string<T>::format(result, fmt_unveil<T>::get(m_value.load()));
return result; // TODO: ???
}
@ -235,7 +237,7 @@ namespace cfg
// Prefer 32 bit type if possible
using int_type = std::conditional_t<Min >= INT32_MIN && Max <= INT32_MAX, s32, s64>;
int_type m_value;
atomic_t<int_type> m_value;
public:
int_type def;
@ -256,7 +258,7 @@ namespace cfg
return m_value;
}
const int_type& get() const
int_type get() const
{
return m_value;
}
@ -303,50 +305,56 @@ namespace cfg
// Simple string entry with mutex
class string final : public _base
{
std::string m_name;
std::string m_value;
const std::string m_name;
stx::atomic_cptr<std::string> m_value;
public:
std::string def;
string(node* owner, const std::string& name, const std::string& def = {}, bool dynamic = false)
string(node* owner, std::string name, std::string def = {}, bool dynamic = false)
: _base(type::string, owner, name, dynamic)
, m_name(name)
, m_value(def)
, def(def)
, m_name(std::move(name))
, m_value(m_value.make(def))
, def(std::move(def))
{
}
operator std::string() const
{
return m_value;
return *m_value.load().get();
}
const std::string& get() const
std::pair<const std::string&, stx::shared_cptr<std::string>> get() const
{
return m_value;
auto v = m_value.load();
if (auto s = v.get())
{
return {*s, std::move(v)};
}
else
{
static const std::string _empty;
return {_empty, {}};
}
}
std::string get_name() const
const std::string& get_name() const
{
return m_name;
}
std::size_t size() const
{
return m_value.size();
}
void from_default() override;
std::string to_string() const override
{
return m_value;
return *m_value.load().get();
}
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
{
m_value = value;
m_value = m_value.make(value);
return true;
}
};

View file

@ -116,7 +116,9 @@ void gdb_thread::start_server()
// IPv4 address:port in format 127.0.0.1:2345
static const std::regex ipv4_regex("^([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})\\:([0-9]{1,5})$");
if (g_cfg.misc.gdb_server.get()[0] == '\0')
auto [sname, sshared] = g_cfg.misc.gdb_server.get();
if (sname[0] == '\0')
{
// Empty string or starts with null: GDB server disabled
GDB.notice("GDB Server is disabled.");
@ -126,7 +128,7 @@ void gdb_thread::start_server()
// Try to detect socket type
std::smatch match;
if (std::regex_match(g_cfg.misc.gdb_server.get(), match, ipv4_regex))
if (std::regex_match(sname, match, ipv4_regex))
{
struct addrinfo hints{};
struct addrinfo* info;
@ -142,7 +144,7 @@ void gdb_thread::start_server()
if (server_socket == -1)
{
GDB.error("Error creating IP socket for '%s'.", g_cfg.misc.gdb_server.get());
GDB.error("Error creating IP socket for '%s'.", sname);
freeaddrinfo(info);
return;
}
@ -151,7 +153,7 @@ void gdb_thread::start_server()
if (bind(server_socket, info->ai_addr, static_cast<int>(info->ai_addrlen)) != 0)
{
GDB.error("Failed to bind socket on '%s'.", g_cfg.misc.gdb_server.get());
GDB.error("Failed to bind socket on '%s'.", sname);
freeaddrinfo(info);
return;
}
@ -160,11 +162,11 @@ void gdb_thread::start_server()
if (listen(server_socket, 1) != 0)
{
GDB.error("Failed to listen on '%s'.", g_cfg.misc.gdb_server.get());
GDB.error("Failed to listen on '%s'.", sname);
return;
}
GDB.notice("Started listening on '%s'.", g_cfg.misc.gdb_server.get());
GDB.notice("Started listening on '%s'.", sname);
return;
}
}
@ -179,27 +181,27 @@ void gdb_thread::start_server()
}
// Delete existing socket (TODO?)
fs::remove_file(g_cfg.misc.gdb_server.get());
fs::remove_file(sname);
set_nonblocking(server_socket);
sockaddr_un unix_saddr;
unix_saddr.sun_family = AF_UNIX;
strcpy_trunc(unix_saddr.sun_path, g_cfg.misc.gdb_server.get());
strcpy_trunc(unix_saddr.sun_path, sname);
if (bind(server_socket, reinterpret_cast<struct sockaddr*>(&unix_saddr), sizeof(unix_saddr)) != 0)
{
GDB.error("Failed to bind Unix socket '%s'.", g_cfg.misc.gdb_server.get());
GDB.error("Failed to bind Unix socket '%s'.", sname);
return;
}
if (listen(server_socket, 1) != 0)
{
GDB.error("Failed to listen on Unix socket '%s'.", g_cfg.misc.gdb_server.get());
GDB.error("Failed to listen on Unix socket '%s'.", sname);
return;
}
GDB.notice("Started listening on Unix socket '%s'.", g_cfg.misc.gdb_server.get());
GDB.notice("Started listening on Unix socket '%s'.", sname);
}
int gdb_thread::read(void* buf, int cnt)

View file

@ -1847,12 +1847,16 @@ void Emulator::Stop(bool restart)
std::string cfg_root::node_vfs::get(const cfg::string& _cfg, const char* _def) const
{
if (_cfg.get().empty())
auto [spath, sshared] = _cfg.get();
if (spath.empty())
{
return fs::get_config_dir() + _def;
}
return fmt::replace_all(_cfg.get(), "$(EmulatorDir)", emulator_dir.get().empty() ? fs::get_config_dir() : emulator_dir.get());
auto [semudir, sshared2] = emulator_dir.get();
return fmt::replace_all(spath, "$(EmulatorDir)", semudir.empty() ? fs::get_config_dir() : semudir);
}
s32 error_code::error_report(const fmt_type_info* sup, u64 arg, const fmt_type_info* sup2, u64 arg2)