From 1de9f30449fbd2acd5de72dc1bac7950fb44808a Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 8 Jan 2018 12:24:36 +0800 Subject: [PATCH] [Server] Fix iterating killed timers when kill() called in the callback Instance new timers before new tick --- apps/openmw-mp/Timer.cpp | 38 +++++++++++++++++++++++++++++--------- apps/openmw-mp/Timer.hpp | 5 +++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/apps/openmw-mp/Timer.cpp b/apps/openmw-mp/Timer.cpp index 86d96fcb4..14deb55e1 100644 --- a/apps/openmw-mp/Timer.cpp +++ b/apps/openmw-mp/Timer.cpp @@ -62,7 +62,7 @@ Timer::~Timer() void Timer::tick() { - if (end) + if (end || markedToDelete) return; const auto duration = chrono::system_clock::now().time_since_epoch(); @@ -81,6 +81,11 @@ void Timer::tick() } } +void Timer::kill() +{ + markedToDelete = true; +} + void TimerController::Init(LuaState &lua) { sol::table timerTable = lua.getState()->create_table("TimerCtrl"); @@ -96,22 +101,37 @@ void TimerController::Init(LuaState &lua) std::shared_ptr TimerController::create(sol::environment env, sol::function callback, long msec, sol::table args) { - timers.emplace_back(new Timer(env, callback, msec, args)); - return timers.back(); + newTimersQueue.emplace_back(new Timer(env, callback, msec, args)); + return newTimersQueue.back(); } void TimerController::kill(const std::shared_ptr &timer) { - auto it = find(timers.begin(), timers.end(), timer); - if (it != timers.end()) - { - LOG_MESSAGE_SIMPLE(Log::LOG_TRACE, "Timer %p killed\n", timer.get()); - timers.erase(it); - } + LOG_MESSAGE_SIMPLE(Log::LOG_TRACE, "Timer %p marked for deletion\n", timer.get()); + timer->kill(); + haveMarkedToDeletion = true; } void TimerController::tick() { + if (haveMarkedToDeletion) + { + size_t deleted = timers.size(); + haveMarkedToDeletion = false; + timers.erase(remove_if(timers.begin(), timers.end(), [](const std::shared_ptr &timer) { + return timer->isMarkedToDelete(); + }), timers.end()); + deleted -= timers.size(); + LOG_MESSAGE_SIMPLE(Log::LOG_TRACE, "Deleted %d timers\n", deleted); + } + + if(!newTimersQueue.empty()) + { + timers.insert(timers.begin(), make_move_iterator(newTimersQueue.begin()), make_move_iterator(newTimersQueue.end())); + LOG_MESSAGE_SIMPLE(Log::LOG_TRACE, "Created %d timers\n", newTimersQueue.size()); + newTimersQueue.clear(); + } + for (auto &timer : timers) { timer->tick(); diff --git a/apps/openmw-mp/Timer.hpp b/apps/openmw-mp/Timer.hpp index 975ecd54f..2c1b51198 100644 --- a/apps/openmw-mp/Timer.hpp +++ b/apps/openmw-mp/Timer.hpp @@ -24,12 +24,15 @@ public: protected: Timer(sol::environment &env, sol::function &callback, long msec, sol::table &args); void tick(); + void kill(); + bool isMarkedToDelete() const { return markedToDelete; } private: double startTime, targetMsec; sol::function callback; sol::table data; sol::environment env; bool end; + bool markedToDelete; }; class TimerController @@ -44,5 +47,7 @@ public: void tick(); private: std::vector> timers; + std::vector> newTimersQueue; + bool haveMarkedToDeletion; };