mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-08-16 16:26:26 +00:00
fix event loop timing issue
The event loop tries to run no faster than every 10ms. If it detects that it goes faster, it would incorrectly calculate the difference, and then wait (what I assume was) way too long or too short. Either way, now it's fixed and it correctly works, even when introducing new lua states.
This commit is contained in:
parent
6a94060970
commit
fd7b11f436
@ -1,3 +1,4 @@
|
||||
|
||||
# v3.1.0
|
||||
|
||||
- ADDED Tab autocomplete in console, smart tab autocomplete (understands lua tables and types) in the lua console
|
||||
@ -9,6 +10,7 @@
|
||||
- FIXED issue with client->server events which contain ':'
|
||||
- FIXED a fatal exception on LuaEngine startup if Resources/Server is a symlink
|
||||
- FIXED onInit not being called on hot-reload
|
||||
- FIXED incorrect timing calculation of Lua EventTimer loop
|
||||
|
||||
# v3.0.2
|
||||
|
||||
|
@ -12,6 +12,7 @@ extern TSentry Sentry;
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <sstream>
|
||||
#include <zlib.h>
|
||||
|
||||
@ -96,6 +97,8 @@ public:
|
||||
static void CheckForUpdates();
|
||||
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
|
||||
static bool IsOutdated(const Version& Current, const Version& Newest);
|
||||
static bool IsShuttingDown();
|
||||
static void SleepSafeSeconds(size_t Seconds);
|
||||
|
||||
static void InitializeConsole() {
|
||||
if (!mConsole) {
|
||||
@ -121,10 +124,14 @@ public:
|
||||
static void SetSubsystemStatus(const std::string& Subsystem, Status status);
|
||||
|
||||
private:
|
||||
static void SetShutdown(bool Val);
|
||||
|
||||
static inline SystemStatusMap mSystemStatusMap {};
|
||||
static inline std::mutex mSystemStatusMapMutex {};
|
||||
static inline std::string mPPS;
|
||||
static inline std::unique_ptr<TConsole> mConsole;
|
||||
static inline std::shared_mutex mShutdownMtx {};
|
||||
static inline bool mShutdown { false };
|
||||
static inline std::mutex mShutdownHandlersMutex {};
|
||||
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
|
||||
|
||||
|
@ -15,7 +15,6 @@ private:
|
||||
std::string GenerateCall();
|
||||
std::string GetPlayers();
|
||||
|
||||
bool mShutdown = false;
|
||||
TResourceManager& mResourceManager;
|
||||
TServer& mServer;
|
||||
};
|
||||
|
@ -187,7 +187,7 @@ private:
|
||||
|
||||
class StateThreadData : IThreaded {
|
||||
public:
|
||||
StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine);
|
||||
StateThreadData(const std::string& Name, TLuaStateId StateId, TLuaEngine& Engine);
|
||||
StateThreadData(const StateThreadData&) = delete;
|
||||
~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); }
|
||||
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(const TLuaChunk& Script);
|
||||
@ -218,7 +218,6 @@ private:
|
||||
sol::table Lua_FS_ListDirectories(const std::string& Path);
|
||||
|
||||
std::string mName;
|
||||
std::atomic_bool& mShutdown;
|
||||
TLuaStateId mStateId;
|
||||
lua_State* mState;
|
||||
std::thread mThread;
|
||||
@ -247,8 +246,7 @@ private:
|
||||
|
||||
TNetwork* mNetwork;
|
||||
TServer* mServer;
|
||||
std::atomic_bool mShutdown { false };
|
||||
fs::path mResourceServerPath;
|
||||
const fs::path mResourceServerPath;
|
||||
std::vector<std::shared_ptr<TLuaPlugin>> mLuaPlugins;
|
||||
std::unordered_map<TLuaStateId, std::unique_ptr<StateThreadData>> mLuaStates;
|
||||
std::recursive_mutex mLuaStatesMutex;
|
||||
|
@ -32,7 +32,6 @@ private:
|
||||
TServer& mServer;
|
||||
TPPSMonitor& mPPSMonitor;
|
||||
SOCKET mUDPSock {};
|
||||
bool mShutdown { false };
|
||||
TResourceManager& mResourceManager;
|
||||
std::thread mUDPThread;
|
||||
std::thread mTCPThread;
|
||||
|
@ -22,6 +22,5 @@ private:
|
||||
|
||||
TServer& mServer;
|
||||
std::optional<std::reference_wrapper<TNetwork>> mNetwork { std::nullopt };
|
||||
bool mShutdown { false };
|
||||
int mInternalPPS { 0 };
|
||||
};
|
||||
};
|
||||
|
@ -18,6 +18,5 @@ public:
|
||||
private:
|
||||
std::shared_ptr<TLuaEngine> mEngine;
|
||||
fs::path mPath;
|
||||
std::atomic_bool mShutdown { false };
|
||||
std::unordered_map<std::string, fs::file_time_type> mFileTimes;
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ void Application::RegisterShutdownHandler(const TShutdownHandler& Handler) {
|
||||
}
|
||||
|
||||
void Application::GracefullyShutdown() {
|
||||
SetShutdown(true);
|
||||
static bool AlreadyShuttingDown = false;
|
||||
static uint8_t ShutdownAttempts = 0;
|
||||
if (AlreadyShuttingDown) {
|
||||
@ -93,6 +94,22 @@ bool Application::IsOutdated(const Version& Current, const Version& Newest) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::IsShuttingDown() {
|
||||
std::shared_lock Lock(mShutdownMtx);
|
||||
return mShutdown;
|
||||
}
|
||||
|
||||
void Application::SleepSafeSeconds(size_t Seconds) {
|
||||
// Sleeps for 500 ms, checks if a shutdown occurred, and so forth
|
||||
for (size_t i = 0; i < Seconds * 2; ++i) {
|
||||
if (Application::IsShuttingDown()) {
|
||||
return;
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Application::IsOutdated (version check)") {
|
||||
SUBCASE("Same version") {
|
||||
CHECK(!Application::IsOutdated({ 1, 2, 3 }, { 1, 2, 3 }));
|
||||
@ -158,6 +175,11 @@ void Application::SetSubsystemStatus(const std::string& Subsystem, Status status
|
||||
mSystemStatusMap[Subsystem] = status;
|
||||
}
|
||||
|
||||
void Application::SetShutdown(bool Val) {
|
||||
std::unique_lock Lock(mShutdownMtx);
|
||||
mShutdown = Val;
|
||||
}
|
||||
|
||||
TEST_CASE("Application::SetSubsystemStatus") {
|
||||
Application::SetSubsystemStatus("Test", Application::Status::Good);
|
||||
auto Map = Application::GetSubsystemStatuses();
|
||||
|
@ -20,7 +20,7 @@ void THeartbeatThread::operator()() {
|
||||
static std::chrono::high_resolution_clock::time_point LastNormalUpdateTime = std::chrono::high_resolution_clock::now();
|
||||
bool isAuth = false;
|
||||
size_t UpdateReminderCounter = 0;
|
||||
while (!mShutdown) {
|
||||
while (!Application::IsShuttingDown()) {
|
||||
++UpdateReminderCounter;
|
||||
Body = GenerateCall();
|
||||
// a hot-change occurs when a setting has changed, to update the backend of that change.
|
||||
@ -164,7 +164,6 @@ THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& S
|
||||
Application::RegisterShutdownHandler([&] {
|
||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::ShuttingDown);
|
||||
if (mThread.joinable()) {
|
||||
mShutdown = true;
|
||||
mThread.join();
|
||||
}
|
||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Shutdown);
|
||||
|
@ -15,20 +15,18 @@
|
||||
|
||||
TLuaEngine* LuaAPI::MP::Engine;
|
||||
|
||||
TLuaEngine::TLuaEngine() {
|
||||
TLuaEngine::TLuaEngine()
|
||||
: mResourceServerPath(fs::path(Application::Settings.Resource) / "Server") {
|
||||
Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting);
|
||||
LuaAPI::MP::Engine = this;
|
||||
if (!fs::exists(Application::Settings.Resource)) {
|
||||
fs::create_directory(Application::Settings.Resource);
|
||||
}
|
||||
fs::path Path = fs::path(Application::Settings.Resource) / "Server";
|
||||
if (!fs::exists(Path)) {
|
||||
fs::create_directory(Path);
|
||||
if (!fs::exists(mResourceServerPath)) {
|
||||
fs::create_directory(mResourceServerPath);
|
||||
}
|
||||
mResourceServerPath = Path;
|
||||
Application::RegisterShutdownHandler([&] {
|
||||
Application::SetSubsystemStatus("LuaEngine", Application::Status::ShuttingDown);
|
||||
mShutdown = true;
|
||||
if (mThread.joinable()) {
|
||||
mThread.join();
|
||||
}
|
||||
@ -59,7 +57,7 @@ void TLuaEngine::operator()() {
|
||||
|
||||
auto ResultCheckThread = std::thread([&] {
|
||||
RegisterThread("ResultCheckThread");
|
||||
while (!mShutdown) {
|
||||
while (!Application::IsShuttingDown()) {
|
||||
std::unique_lock Lock(mResultsToCheckMutex);
|
||||
mResultsToCheckCond.wait_for(Lock, std::chrono::milliseconds(20));
|
||||
if (!mResultsToCheck.empty()) {
|
||||
@ -79,10 +77,7 @@ void TLuaEngine::operator()() {
|
||||
});
|
||||
// event loop
|
||||
auto Before = std::chrono::high_resolution_clock::now();
|
||||
while (!mShutdown) {
|
||||
if (mLuaStates.size() == 0) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(100));
|
||||
}
|
||||
while (!Application::IsShuttingDown()) {
|
||||
{ // Timed Events Scope
|
||||
std::unique_lock Lock(mTimedEventsMutex);
|
||||
for (auto& Timer : mTimedEvents) {
|
||||
@ -108,12 +103,18 @@ void TLuaEngine::operator()() {
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto Expected = std::chrono::milliseconds(10);
|
||||
if (auto Diff = std::chrono::high_resolution_clock::now() - Before;
|
||||
Diff < Expected) {
|
||||
std::this_thread::sleep_for(Expected - Diff);
|
||||
if (mLuaStates.size() == 0) {
|
||||
beammp_trace("No Lua states, event loop running extremely sparsely");
|
||||
Application::SleepSafeSeconds(10);
|
||||
} else {
|
||||
beammp_trace("Event loop cannot keep up! Running " + std::to_string(Diff.count()) + "s behind");
|
||||
constexpr double NsFactor = 1000000.0;
|
||||
constexpr double Expected = 10.0; // ms
|
||||
const auto Diff = (std::chrono::high_resolution_clock::now() - Before).count() / NsFactor;
|
||||
if (Diff < Expected) {
|
||||
std::this_thread::sleep_for(std::chrono::nanoseconds(size_t((Expected - Diff) * NsFactor)));
|
||||
} else {
|
||||
beammp_tracef("Event loop cannot keep up! Running {}ms behind", Diff);
|
||||
}
|
||||
}
|
||||
Before = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
@ -326,7 +327,7 @@ void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name,
|
||||
std::unique_lock Lock(mLuaStatesMutex);
|
||||
if (mLuaStates.find(StateId) == mLuaStates.end()) {
|
||||
beammp_debug("Creating lua state for state id \"" + StateId + "\"");
|
||||
auto DataPtr = std::make_unique<StateThreadData>(Name, mShutdown, StateId, *this);
|
||||
auto DataPtr = std::make_unique<StateThreadData>(Name, StateId, *this);
|
||||
mLuaStates[StateId] = std::move(DataPtr);
|
||||
RegisterEvent("onInit", StateId, "onInit");
|
||||
if (!DontCallOnInit) {
|
||||
@ -614,9 +615,8 @@ sol::table TLuaEngine::StateThreadData::Lua_JsonDecode(const std::string& str) {
|
||||
return table;
|
||||
}
|
||||
|
||||
TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine)
|
||||
TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateId StateId, TLuaEngine& Engine)
|
||||
: mName(Name)
|
||||
, mShutdown(Shutdown)
|
||||
, mStateId(StateId)
|
||||
, mState(luaL_newstate())
|
||||
, mEngine(&Engine) {
|
||||
@ -819,7 +819,7 @@ void TLuaEngine::StateThreadData::RegisterEvent(const std::string& EventName, co
|
||||
|
||||
void TLuaEngine::StateThreadData::operator()() {
|
||||
RegisterThread("Lua:" + mStateId);
|
||||
while (!mShutdown) {
|
||||
while (!Application::IsShuttingDown()) {
|
||||
{ // StateExecuteQueue Scope
|
||||
std::unique_lock Lock(mStateExecuteQueueMutex);
|
||||
if (!mStateExecuteQueue.empty()) {
|
||||
|
@ -25,7 +25,6 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
|
||||
Application::RegisterShutdownHandler([&] {
|
||||
Application::SetSubsystemStatus("UDPNetwork", Application::Status::ShuttingDown);
|
||||
if (mUDPThread.joinable()) {
|
||||
mShutdown = true;
|
||||
mUDPThread.detach();
|
||||
}
|
||||
Application::SetSubsystemStatus("UDPNetwork", Application::Status::Shutdown);
|
||||
@ -33,7 +32,6 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
|
||||
Application::RegisterShutdownHandler([&] {
|
||||
Application::SetSubsystemStatus("TCPNetwork", Application::Status::ShuttingDown);
|
||||
if (mTCPThread.joinable()) {
|
||||
mShutdown = true;
|
||||
mTCPThread.detach();
|
||||
}
|
||||
Application::SetSubsystemStatus("TCPNetwork", Application::Status::Shutdown);
|
||||
@ -68,7 +66,7 @@ void TNetwork::UDPServerMain() {
|
||||
Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good);
|
||||
beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ")
|
||||
+ std::to_string(Application::Settings.MaxPlayers) + (" Clients"));
|
||||
while (!mShutdown) {
|
||||
while (!Application::IsShuttingDown()) {
|
||||
try {
|
||||
sockaddr_in client {};
|
||||
std::string Data = UDPRcvFromClient(client); // Receives any data from Socket
|
||||
@ -152,7 +150,7 @@ void TNetwork::TCPServerMain() {
|
||||
beammp_info("Vehicle event network online");
|
||||
do {
|
||||
try {
|
||||
if (mShutdown) {
|
||||
if (Application::IsShuttingDown()) {
|
||||
beammp_debug("shutdown during TCP wait for accept loop");
|
||||
break;
|
||||
}
|
||||
@ -239,16 +237,16 @@ void TNetwork::HandleDownload(SOCKET TCPSock) {
|
||||
});
|
||||
}
|
||||
|
||||
static int get_ip_str(const struct sockaddr *sa, char *strBuf, size_t strBufSize) {
|
||||
switch(sa->sa_family) {
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), strBuf, strBufSize);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), strBuf, strBufSize);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
static int get_ip_str(const struct sockaddr* sa, char* strBuf, size_t strBufSize) {
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in*)sa)->sin_addr), strBuf, strBufSize);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, &(((struct sockaddr_in6*)sa)->sin6_addr), strBuf, strBufSize);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ TPPSMonitor::TPPSMonitor(TServer& Server)
|
||||
Application::SetSubsystemStatus("PPSMonitor", Application::Status::ShuttingDown);
|
||||
if (mThread.joinable()) {
|
||||
beammp_debug("shutting down PPSMonitor");
|
||||
mShutdown = true;
|
||||
mThread.join();
|
||||
beammp_debug("shut down PPSMonitor");
|
||||
}
|
||||
@ -27,7 +26,7 @@ void TPPSMonitor::operator()() {
|
||||
beammp_debug("PPSMonitor starting");
|
||||
Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good);
|
||||
std::vector<std::shared_ptr<TClient>> TimedOutClients;
|
||||
while (!mShutdown) {
|
||||
while (!Application::IsShuttingDown()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
int C = 0, V = 0;
|
||||
if (mServer.ClientCount() == 0) {
|
||||
|
@ -17,7 +17,6 @@ TPluginMonitor::TPluginMonitor(const fs::path& Path, std::shared_ptr<TLuaEngine>
|
||||
}
|
||||
|
||||
Application::RegisterShutdownHandler([this] {
|
||||
mShutdown = true;
|
||||
if (mThread.joinable()) {
|
||||
mThread.join();
|
||||
}
|
||||
@ -30,7 +29,7 @@ void TPluginMonitor::operator()() {
|
||||
RegisterThread("PluginMonitor");
|
||||
beammp_info("PluginMonitor started");
|
||||
Application::SetSubsystemStatus("PluginMonitor", Application::Status::Good);
|
||||
while (!mShutdown) {
|
||||
while (!Application::IsShuttingDown()) {
|
||||
std::vector<std::string> ToRemove;
|
||||
for (const auto& Pair : mFileTimes) {
|
||||
try {
|
||||
@ -61,7 +60,7 @@ void TPluginMonitor::operator()() {
|
||||
} catch (const std::exception& e) {
|
||||
ToRemove.push_back(Pair.first);
|
||||
}
|
||||
for (size_t i = 0; i < 3 && !mShutdown; ++i) {
|
||||
for (size_t i = 0; i < 3 && !Application::IsShuttingDown(); ++i) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ int main(int argc, char** argv) {
|
||||
Sentry.LogException(e, _file_basename, _line);
|
||||
MainRet = -1;
|
||||
}
|
||||
return MainRet;
|
||||
std::exit(MainRet);
|
||||
}
|
||||
|
||||
int BeamMPServerMain(MainArguments Arguments) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user