Merge pull request #573 from diamante0018/feature/scoped-crit-sections

Feature: Scoped crit sections
This commit is contained in:
Edo 2022-11-22 00:32:07 +01:00 committed by GitHub
commit c23557ff9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 17 deletions

View File

@ -1,4 +1,5 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "Game/Engine/ScopedCriticalSection.hpp"
namespace Components namespace Components
{ {
@ -288,7 +289,7 @@ namespace Components
sprintf_s(newFileName, "%s_%s.log", bug, Game::Live_GetLocalClientName(0)); sprintf_s(newFileName, "%s_%s.log", bug, Game::Live_GetLocalClientName(0));
Game::Sys_EnterCriticalSection(Game::CRITSECT_CONSOLE); Game::Engine::ScopedCriticalSection _(Game::CRITSECT_CONSOLE, Game::Engine::SCOPED_CRITSECT_NORMAL);
if (*Game::logfile) if (*Game::logfile)
{ {
@ -301,8 +302,6 @@ namespace Components
const auto result = CopyFileA(from_ospath, to_ospath, 0); const auto result = CopyFileA(from_ospath, to_ospath, 0);
Game::Com_OpenLogFile(); Game::Com_OpenLogFile();
Game::Sys_LeaveCriticalSection(Game::CRITSECT_CONSOLE);
if (!result) if (!result)
{ {
Logger::PrintError(1, "CopyFile failed({}) {} {}\n", GetLastError(), "console_mp.log", newFileName); Logger::PrintError(1, "CopyFile failed({}) {} {}\n", GetLastError(), "console_mp.log", newFileName);

View File

@ -0,0 +1,82 @@
#include <STDInclude.hpp>
#include "ScopedCriticalSection.hpp"
namespace Game::Engine
{
ScopedCriticalSection::ScopedCriticalSection(const CriticalSection s, const ScopedCriticalSectionType type)
: s_(s), isScopedRelease_(false)
{
if (type == SCOPED_CRITSECT_NORMAL)
{
Sys_EnterCriticalSection(this->s_);
this->hasOwnership_ = true;
}
else
{
if (type == SCOPED_CRITSECT_TRY)
{
this->hasOwnership_ = Sys_TryEnterCriticalSection(this->s_);
}
else
{
if (type == SCOPED_CRITSECT_RELEASE)
{
Sys_LeaveCriticalSection(this->s_);
this->isScopedRelease_ = true;
}
this->hasOwnership_ = false;
}
}
}
ScopedCriticalSection::~ScopedCriticalSection()
{
if (!this->hasOwnership_ || this->isScopedRelease_)
{
if (!this->hasOwnership_ && this->isScopedRelease_)
{
Sys_EnterCriticalSection(this->s_);
}
}
else
{
Sys_LeaveCriticalSection(this->s_);
}
}
void ScopedCriticalSection::enterCritSect()
{
assert(!this->hasOwnership_);
this->hasOwnership_ = true;
Sys_EnterCriticalSection(this->s_);
}
void ScopedCriticalSection::leaveCritSect()
{
assert(this->hasOwnership_);
this->hasOwnership_ = false;
Sys_LeaveCriticalSection(this->s_);
}
bool ScopedCriticalSection::tryEnterCritSect()
{
assert(!this->hasOwnership_);
const auto result = Sys_TryEnterCriticalSection(this->s_);
this->hasOwnership_ = result;
return result;
}
bool ScopedCriticalSection::hasOwnership() const
{
return this->hasOwnership_;
}
bool ScopedCriticalSection::isScopedRelease() const
{
return this->isScopedRelease_;
}
}

View File

@ -0,0 +1,31 @@
#pragma once
namespace Game::Engine
{
enum ScopedCriticalSectionType
{
SCOPED_CRITSECT_NORMAL = 0x0,
SCOPED_CRITSECT_DISABLED = 0x1,
SCOPED_CRITSECT_RELEASE = 0x2,
SCOPED_CRITSECT_TRY = 0x3,
};
class ScopedCriticalSection
{
public:
ScopedCriticalSection(CriticalSection s, ScopedCriticalSectionType type);
~ScopedCriticalSection();
void enterCritSect();
void leaveCritSect();
[[nodiscard]] bool tryEnterCritSect();
[[nodiscard]] bool hasOwnership() const;
[[nodiscard]] bool isScopedRelease() const;
private:
CriticalSection s_;
bool hasOwnership_;
bool isScopedRelease_;
};
}

View File

@ -24,6 +24,8 @@ namespace Game
char(*sys_exitCmdLine)[1024] = reinterpret_cast<char(*)[1024]>(0x649FB68); char(*sys_exitCmdLine)[1024] = reinterpret_cast<char(*)[1024]>(0x649FB68);
RTL_CRITICAL_SECTION* s_criticalSection = reinterpret_cast<RTL_CRITICAL_SECTION*>(0x6499BC8);
void Sys_LockRead(FastCriticalSection* critSect) void Sys_LockRead(FastCriticalSection* critSect)
{ {
InterlockedIncrement(&critSect->readCount); InterlockedIncrement(&critSect->readCount);
@ -35,4 +37,12 @@ namespace Game
assert(critSect->readCount > 0); assert(critSect->readCount > 0);
InterlockedDecrement(&critSect->readCount); InterlockedDecrement(&critSect->readCount);
} }
bool Sys_TryEnterCriticalSection(CriticalSection critSect)
{
assert(static_cast<unsigned int>(critSect) <
static_cast<unsigned int>(CRITSECT_COUNT));
return TryEnterCriticalSection(&s_criticalSection[critSect]) != FALSE;
}
} }

View File

@ -62,6 +62,10 @@ namespace Game
extern char(*sys_exitCmdLine)[1024]; extern char(*sys_exitCmdLine)[1024];
extern RTL_CRITICAL_SECTION* s_criticalSection;
extern void Sys_LockRead(FastCriticalSection* critSect); extern void Sys_LockRead(FastCriticalSection* critSect);
extern void Sys_UnlockRead(FastCriticalSection* critSect); extern void Sys_UnlockRead(FastCriticalSection* critSect);
extern bool Sys_TryEnterCriticalSection(CriticalSection critSect);
} }

View File

@ -162,31 +162,31 @@ namespace Steam
Interface clientUtils(Proxy::ClientEngine->GetIClientUtils(Proxy::SteamPipe)); Interface clientUtils(Proxy::ClientEngine->GetIClientUtils(Proxy::SteamPipe));
clientUtils.invoke<void>("SetAppIDForCurrentPipe", Proxy::AppId, false); clientUtils.invoke<void>("SetAppIDForCurrentPipe", Proxy::AppId, false);
char ourPath[MAX_PATH] = {0}; char ourPath[MAX_PATH]{};
GetModuleFileNameA(GetModuleHandle(nullptr), ourPath, sizeof(ourPath)); GetModuleFileNameA(GetModuleHandle(nullptr), ourPath, sizeof(ourPath));
char ourDirectory[MAX_PATH] = { 0 }; char ourDirectory[MAX_PATH]{};
GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory); GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory);
std::string cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId()); const auto* cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId());
// As of 02/19/2017, the SpawnProcess method doesn't require the app id anymore, // As of 02/19/2017, the SpawnProcess method doesn't require the app id anymore,
// but only for those who participate in the beta. // but only for those who participate in the beta.
// Therefore we have to check how many bytes the method expects as arguments // Therefore we have to check how many bytes the method expects as arguments
// and adapt our call accordingly! // and adapt our call accordingly!
size_t expectedParams = Proxy::ClientUser.paramSize("SpawnProcess"); const auto expectedParams = Proxy::ClientUser.paramSize("SpawnProcess");
if (expectedParams == 40) // Release if (expectedParams == 40) // Release
{ {
Proxy::ClientUser.invoke<bool>("SpawnProcess", ourPath, cmdline.data(), ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0); Proxy::ClientUser.invoke<bool>("SpawnProcess", ourPath, cmdline, ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0, 0);
} }
else if (expectedParams == 36) // Beta else if (expectedParams == 36) // Beta
{ {
Proxy::ClientUser.invoke<bool>("SpawnProcess", ourPath, cmdline.data(), ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0); Proxy::ClientUser.invoke<bool>("SpawnProcess", ourPath, cmdline, ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0);
} }
else if (expectedParams == 48) // Legacy, expects VAC blob else if (expectedParams == 48) // Legacy, expects VAC blob
{ {
char blob[8] = { 0 }; char blob[8] = { 0 };
Proxy::ClientUser.invoke<bool>("SpawnProcess", blob, 0, ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0); Proxy::ClientUser.invoke<bool>("SpawnProcess", blob, 0, ourPath, cmdline, 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0);
} }
else else
{ {
@ -260,7 +260,7 @@ namespace Steam
Proxy::Callbacks.erase(callId); Proxy::Callbacks.erase(callId);
} }
void Proxy::RunCallback(int32_t callId, void* data, size_t /*size*/) void Proxy::RunCallback(int32_t callId, void* data, std::size_t /*size*/)
{ {
std::lock_guard<std::recursive_mutex> _(Proxy::CallMutex); std::lock_guard<std::recursive_mutex> _(Proxy::CallMutex);

View File

@ -169,8 +169,8 @@ namespace Steam
return T(); return T();
} }
size_t argc = method.second; std::size_t argc = method.second;
constexpr size_t passedArgc = Interface::AddSizes<sizeof(Args)...>::value; constexpr std::size_t passedArgc = Interface::AddSizes<sizeof(Args)...>::value;
if(passedArgc != argc) if(passedArgc != argc)
{ {
OutputDebugStringA(::Utils::String::VA("Steam interface arguments for method %s do not match (expected %d bytes, but got %d bytes)!\n", methodName.data(), argc, passedArgc)); OutputDebugStringA(::Utils::String::VA("Steam interface arguments for method %s do not match (expected %d bytes, but got %d bytes)!\n", methodName.data(), argc, passedArgc));
@ -185,7 +185,7 @@ namespace Steam
return this->interfacePtr != nullptr; return this->interfacePtr != nullptr;
} }
size_t paramSize(const std::string& methodName) std::size_t paramSize(const std::string& methodName)
{ {
auto method = this->getMethod(methodName); auto method = this->getMethod(methodName);
return method.second; return method.second;
@ -222,9 +222,9 @@ namespace Steam
private: private:
std::string buffer; std::string buffer;
inline void packBytes(const void* bytes, size_t size) inline void packBytes(const void* bytes, std::size_t size)
{ {
this->buffer.append(reinterpret_cast<const char*>(bytes), size); this->buffer.append(static_cast<const char*>(bytes), size);
} }
inline void packDataType(uint8_t type) inline void packDataType(uint8_t type)
@ -358,7 +358,7 @@ namespace Steam
static std::function<SteamFreeLastCallbackFn> SteamFreeLastCallback; static std::function<SteamFreeLastCallbackFn> SteamFreeLastCallback;
static std::function<SteamGetAPICallResultFn> SteamGetAPICallResult; static std::function<SteamGetAPICallResultFn> SteamGetAPICallResult;
static void RunCallback(int32_t callId, void* data, size_t size); static void RunCallback(int32_t callId, void* data, std::size_t size);
static void UnregisterCalls(); static void UnregisterCalls();
static void LaunchWatchGuard(); static void LaunchWatchGuard();