From a1f33ffd9fc38e242026f210cb45fbc946b3a7c7 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Tue, 31 Mar 2015 19:52:19 +0200 Subject: [PATCH] Added and updated map mthread Thanks to the original mtmaps and openmaps creators --- src/game/CMakeLists.txt | 13 ++- src/game/Maps/MapUpdater.cpp | 151 +++++++++++++++++++++++++ src/game/Maps/MapUpdater.h | 64 +++++++++++ src/game/WorldHandlers/MapManager.cpp | 24 +++- src/game/WorldHandlers/MapManager.h | 2 + src/game/WorldHandlers/World.cpp | 2 + src/game/WorldHandlers/World.h | 1 + src/mangosd/CMakeLists.txt | 1 + src/mangosd/mangosd.conf.dist.in | 5 + src/modules/Eluna | 2 +- src/shared/Threading/DelayExecutor.cpp | 135 ++++++++++++++++++++++ src/shared/Threading/DelayExecutor.h | 61 ++++++++++ 12 files changed, 457 insertions(+), 4 deletions(-) create mode 100644 src/game/Maps/MapUpdater.cpp create mode 100644 src/game/Maps/MapUpdater.h create mode 100644 src/shared/Threading/DelayExecutor.cpp create mode 100644 src/shared/Threading/DelayExecutor.h diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index fb906eef..161817f3 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -23,6 +23,7 @@ include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouseBot" "${CMAKE_CURRENT_SOURCE_DIR}/BattleGround" "${CMAKE_CURRENT_SOURCE_DIR}/ChatCommands" + "${CMAKE_CURRENT_SOURCE_DIR}/Maps" "${CMAKE_CURRENT_SOURCE_DIR}/MotionGenerators" "${CMAKE_CURRENT_SOURCE_DIR}/Object" "${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP" @@ -39,9 +40,11 @@ include_directories( "${CMAKE_SOURCE_DIR}/dep/include" "${CMAKE_SOURCE_DIR}/src/shared" "${CMAKE_SOURCE_DIR}/src/shared/Common" + "${CMAKE_SOURCE_DIR}/src/shared/Database" + "${CMAKE_SOURCE_DIR}/src/shared/DataStores" "${CMAKE_SOURCE_DIR}/src/shared/Utilities" "${CMAKE_SOURCE_DIR}/src/shared/Log" - "${CMAKE_SOURCE_DIR}/src/shared/DataStores" + "${CMAKE_SOURCE_DIR}/src/shared/Threading" "${CMAKE_SOURCE_DIR}/src/framework" "${CMAKE_BINARY_DIR}/src/shared" "${MYSQL_INCLUDE_DIR}" @@ -71,6 +74,13 @@ source_group("Chat Commands" ${SRC_GRP_CHAT_COMMANDS} ) +#Map Threading group +file(GLOB SRC_GRP_MAP_THREAD Maps/*.cpp Maps/*.h) +source_group("Map Threading" + FILES + ${SRC_GRP_MAP_THREAD} +) + #Motion Generator group file(GLOB SRC_GRP_MOTION_GEN MotionGenerators/*.cpp MotionGenerators/*.h) source_group("Motion generators" @@ -138,6 +148,7 @@ set(LIBRARY_SRCS ${SRC_GRP_AHBOT} ${SRC_GRP_BATTLEGROUND} ${SRC_GRP_CHAT_COMMANDS} + ${SRC_GRP_MAP_THREAD} ${SRC_GRP_MOTION_GEN} ${SRC_GRP_MOVEMENT} ${SRC_GRP_OBJECT} diff --git a/src/game/Maps/MapUpdater.cpp b/src/game/Maps/MapUpdater.cpp new file mode 100644 index 00000000..244305e3 --- /dev/null +++ b/src/game/Maps/MapUpdater.cpp @@ -0,0 +1,151 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2015 MaNGOS project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#include "MapUpdater.h" +#include "DelayExecutor.h" +#include "Map.h" +#include "DatabaseEnv.h" + +#include +#include + +class WDBThreadStartReq1 : public ACE_Method_Request +{ + public: + + WDBThreadStartReq1() + { + } + + virtual int call() + { + return 0; + } +}; + +class WDBThreadEndReq1 : public ACE_Method_Request +{ + public: + + WDBThreadEndReq1() + { + } + + virtual int call() + { + return 0; + } +}; + +class MapUpdateRequest : public ACE_Method_Request +{ + private: + + Map& m_map; + MapUpdater& m_updater; + ACE_UINT32 m_diff; + + public: + + MapUpdateRequest(Map& m, MapUpdater& u, ACE_UINT32 d) + : m_map(m), m_updater(u), m_diff(d) + { + } + + virtual int call() + { + m_map.Update (m_diff); + m_updater.update_finished(); + return 0; + } +}; + +MapUpdater::MapUpdater(): +m_executor(), m_mutex(), m_condition(m_mutex), pending_requests(0) +{ +} + +MapUpdater::~MapUpdater() +{ + deactivate(); +} + +int MapUpdater::activate(size_t num_threads) +{ + return m_executor.activate((int)num_threads, new WDBThreadStartReq1, new WDBThreadEndReq1); +} + +int MapUpdater::deactivate() +{ + wait(); + + return m_executor.deactivate(); +} + +int MapUpdater::wait() +{ + ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, m_mutex, -1); + + while (pending_requests > 0) + m_condition.wait(); + + return 0; +} + +int MapUpdater::schedule_update(Map& map, ACE_UINT32 diff) +{ + ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, m_mutex, -1); + + ++pending_requests; + + if (m_executor.execute(new MapUpdateRequest(map, *this, diff)) == -1) + { + ACE_DEBUG((LM_ERROR, ACE_TEXT("(%t) \n"), ACE_TEXT("Failed to schedule Map Update"))); + + --pending_requests; + return -1; + } + + return 0; +} + +bool MapUpdater::activated() +{ + return m_executor.activated(); +} + +void MapUpdater::update_finished() +{ + ACE_GUARD(ACE_Thread_Mutex, guard, m_mutex); + + if (pending_requests == 0) + { + ACE_ERROR((LM_ERROR, ACE_TEXT("(%t)\n"), ACE_TEXT("MapUpdater::update_finished BUG, report to devs"))); + return; + } + + --pending_requests; + + m_condition.broadcast(); +} \ No newline at end of file diff --git a/src/game/Maps/MapUpdater.h b/src/game/Maps/MapUpdater.h new file mode 100644 index 00000000..bbd407a9 --- /dev/null +++ b/src/game/Maps/MapUpdater.h @@ -0,0 +1,64 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2015 MaNGOS project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#ifndef _MAP_UPDATER_H_INCLUDED +#define _MAP_UPDATER_H_INCLUDED + +#include +#include + +#include "DelayExecutor.h" + +class Map; + +class MapUpdater +{ + public: + + MapUpdater(); + virtual ~MapUpdater(); + + friend class MapUpdateRequest; + + int schedule_update(Map& map, ACE_UINT32 diff); + + int wait(); + + int activate(size_t num_threads); + + int deactivate(); + + bool activated(); + + private: + + DelayExecutor m_executor; + ACE_Thread_Mutex m_mutex; + ACE_Condition_Thread_Mutex m_condition; + size_t pending_requests; + + void update_finished(); +}; + +#endif //_MAP_UPDATER_H_INCLUDED \ No newline at end of file diff --git a/src/game/WorldHandlers/MapManager.cpp b/src/game/WorldHandlers/MapManager.cpp index db86ffc8..dbf34d5f 100644 --- a/src/game/WorldHandlers/MapManager.cpp +++ b/src/game/WorldHandlers/MapManager.cpp @@ -58,6 +58,11 @@ MapManager::~MapManager() void MapManager::Initialize() { + int num_threads(sWorld.getConfig(CONFIG_UINT32_NUMTHREADS)); + // Start mtmaps if needed. + if (num_threads > 0 && m_updater.activate(num_threads) == -1) + abort(); + InitStateMachine(); InitMaxInstanceId(); } @@ -180,8 +185,16 @@ void MapManager::Update(uint32 diff) if (!i_timer.Passed()) { return; } - for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter) - { iter->second->Update((uint32)i_timer.GetCurrent()); } + for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) + { + if (m_updater.activated()) + m_updater.schedule_update(*iter->second, (uint32)i_timer.GetCurrent()); + else + iter->second->Update((uint32)i_timer.GetCurrent()); + } + + if (m_updater.activated()) + m_updater.wait(); for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter) { @@ -244,6 +257,9 @@ void MapManager::UnloadAll() } TerrainManager::Instance().UnloadAll(); + + if (m_updater.activated()) + m_updater.deactivate(); } void MapManager::InitMaxInstanceId() @@ -260,6 +276,8 @@ void MapManager::InitMaxInstanceId() uint32 MapManager::GetNumInstances() { + Guard guard(*this); + uint32 ret = 0; for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) { @@ -272,6 +290,8 @@ uint32 MapManager::GetNumInstances() uint32 MapManager::GetNumPlayersInInstances() { + Guard guard(*this); + uint32 ret = 0; for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) { diff --git a/src/game/WorldHandlers/MapManager.h b/src/game/WorldHandlers/MapManager.h index fb017055..d72f4a7d 100644 --- a/src/game/WorldHandlers/MapManager.h +++ b/src/game/WorldHandlers/MapManager.h @@ -31,6 +31,7 @@ #include #include "Map.h" #include "GridStates.h" +#include "MapUpdater.h" class Transport; class BattleGround; @@ -183,6 +184,7 @@ class MapManager : public MaNGOS::Singleton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#include +#include +#include + +#include "DelayExecutor.h" + +DelayExecutor* DelayExecutor::instance() +{ + return ACE_Singleton::instance(); +} + +DelayExecutor::DelayExecutor() + : pre_svc_hook_(0), post_svc_hook_(0), activated_(false) +{ +} + +DelayExecutor::~DelayExecutor() +{ + if (pre_svc_hook_) + delete pre_svc_hook_; + + if (post_svc_hook_) + delete post_svc_hook_; + + deactivate(); +} + +int DelayExecutor::deactivate() +{ + if (!activated()) + return -1; + + activated(false); + queue_.queue()->deactivate(); + wait(); + + return 0; +} + +int DelayExecutor::svc() +{ + if (pre_svc_hook_) + pre_svc_hook_->call(); + + for (;;) + { + ACE_Method_Request* rq = queue_.dequeue(); + + if (!rq) + break; + + rq->call(); + delete rq; + } + + if (post_svc_hook_) + post_svc_hook_->call(); + + return 0; +} + +int DelayExecutor::activate(int num_threads, ACE_Method_Request* pre_svc_hook, ACE_Method_Request* post_svc_hook) +{ + if (activated()) + return -1; + + if (num_threads < 1) + return -1; + + if (pre_svc_hook_) + delete pre_svc_hook_; + + if (post_svc_hook_) + delete post_svc_hook_; + + pre_svc_hook_ = pre_svc_hook; + post_svc_hook_ = post_svc_hook; + + queue_.queue()->activate(); + + if (ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, num_threads) == -1) + return -1; + + activated(true); + + return true; +} + +int DelayExecutor::execute(ACE_Method_Request* new_req) +{ + if (new_req == NULL) + return -1; + + if (queue_.enqueue(new_req, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) + { + delete new_req; + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%t) %p\n"), ACE_TEXT("DelayExecutor::execute enqueue")), -1); + } + + return 0; +} + +bool DelayExecutor::activated() +{ + return activated_; +} + +void DelayExecutor::activated(bool s) +{ + activated_ = s; +} \ No newline at end of file diff --git a/src/shared/Threading/DelayExecutor.h b/src/shared/Threading/DelayExecutor.h new file mode 100644 index 00000000..f86a6e83 --- /dev/null +++ b/src/shared/Threading/DelayExecutor.h @@ -0,0 +1,61 @@ +/** + * MaNGOS is a full featured server for World of Warcraft, supporting + * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 + * + * Copyright (C) 2005-2015 MaNGOS project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * World of Warcraft, and all World of Warcraft or Warcraft art, images, + * and lore are copyrighted by Blizzard Entertainment, Inc. + */ + +#ifndef _M_DELAY_EXECUTOR_H +#define _M_DELAY_EXECUTOR_H + +#include +#include +#include + +class DelayExecutor : protected ACE_Task_Base +{ + public: + + DelayExecutor(); + virtual ~DelayExecutor(); + + static DelayExecutor* instance(); + + int execute(ACE_Method_Request* new_req); + + int activate(int num_threads = 1, ACE_Method_Request* pre_svc_hook = NULL, ACE_Method_Request* post_svc_hook = NULL); + + int deactivate(); + + bool activated(); + + virtual int svc(); + + private: + + ACE_Activation_Queue queue_; + ACE_Method_Request* pre_svc_hook_; + ACE_Method_Request* post_svc_hook_; + bool activated_; + + void activated(bool s); +}; + +#endif // _M_DELAY_EXECUTOR_H \ No newline at end of file