Refactored both world and auth main

- Master/Worldrunable removed
- World Update loop now running on main (which was doing nothing before)
- Processpriority moved to shared
- Added a preliminary thread pool for boost::asio::io_service
This commit is contained in:
leak
2014-07-04 15:22:06 +02:00
parent 4f2f9e08f8
commit 021e18d152
9 changed files with 624 additions and 836 deletions

View File

@@ -24,28 +24,24 @@
* authentication server
*/
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <iostream>
#include <cstdlib>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Configuration/Config.h"
#include "Log.h"
#include "SystemConfig.h"
#include "Util.h"
#include "RealmList.h"
#include "AsyncAcceptor.h"
#include "AuthSession.h"
#include "Common.h"
#include "Configuration/Config.h"
#include "Database/DatabaseEnv.h"
#include "Log.h"
#include "ProcessPriority.h"
#include "RealmList.h"
#include "SystemConfig.h"
#include "Util.h"
#ifdef __linux__
#include <sched.h>
#include <sys/resource.h>
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
#endif
using boost::asio::ip::tcp;
#ifndef _TRINITY_REALM_CONFIG
# define _TRINITY_REALM_CONFIG "authserver.conf"
@@ -53,51 +49,15 @@
bool StartDB();
void StopDB();
void SetProcessPriority();
void SignalHandler(const boost::system::error_code& error, int signalNumber);
void KeepDatabaseAliveHandler(const boost::system::error_code& error);
void usage(const char* prog);
boost::asio::io_service _ioService;
boost::asio::deadline_timer _dbPingTimer(_ioService);
uint32 _dbPingInterval;
LoginDatabaseWorkerPool LoginDatabase;
LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database
using boost::asio::ip::tcp;
void SignalHandler(const boost::system::error_code& error, int signalNumber)
{
if (!error)
{
switch (signalNumber)
{
case SIGINT:
case SIGTERM:
_ioService.stop();
break;
}
}
}
void KeepDatabaseAliveHandler(const boost::system::error_code& error)
{
if (!error)
{
TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
LoginDatabase.KeepAlive();
_dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
}
}
/// Print out the usage string for this program on the console.
void usage(const char* prog)
{
TC_LOG_INFO("server.authserver", "Usage: \n %s [<options>]\n"
" -c config_file use config_file as configuration file\n\r",
prog);
}
/// Launch the auth server
int main(int argc, char** argv)
{
// Command line parsing to get the configuration file name
@@ -129,7 +89,6 @@ int main(int argc, char** argv)
TC_LOG_INFO("server.authserver", "%s (authserver)", _FULLVERSION);
TC_LOG_INFO("server.authserver", "<Ctrl-C> to stop.\n");
TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile);
TC_LOG_INFO("server.authserver", "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
// authserver PID file creation
@@ -158,31 +117,30 @@ int main(int argc, char** argv)
return 1;
}
// Launch the listening network socket
// Start the listening port (acceptor) for auth connections
int32 port = sConfigMgr->GetIntDefault("RealmServerPort", 3724);
if (port < 0 || port > 0xFFFF)
{
TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)");
return 1;
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port);
// Set signal handlers
boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
signals.async_wait(SignalHandler);
SetProcessPriority();
// Set process priority according to configuration settings
SetProcessPriority("server.authserver");
// Enabled a timed callback for handling the database keep alive ping
_dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30);
_dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval));
_dbPingTimer.async_wait(KeepDatabaseAliveHandler);
// Start the io service
// Start the io service worker loop
_ioService.run();
// Close the Database Pool and library
@@ -238,73 +196,35 @@ void StopDB()
MySQL::Library_End();
}
void SetProcessPriority()
void SignalHandler(const boost::system::error_code& error, int signalNumber)
{
#if defined(_WIN32) || defined(__linux__)
///- Handle affinity for multiple processors and process priority
uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0);
bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false);
#ifdef _WIN32 // Windows
HANDLE hProcess = GetCurrentProcess();
if (affinity > 0)
if (!error)
{
ULONG_PTR appAff;
ULONG_PTR sysAff;
if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
switch (signalNumber)
{
// remove non accessible processors
ULONG_PTR currentAffinity = affinity & appAff;
if (!currentAffinity)
TC_LOG_ERROR("server.authserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x", affinity, appAff);
else if (SetProcessAffinityMask(hProcess, currentAffinity))
TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity);
else
TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity);
case SIGINT:
case SIGTERM:
_ioService.stop();
break;
}
}
if (highPriority)
{
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
TC_LOG_INFO("server.authserver", "authserver process priority class set to HIGH");
else
TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class.");
}
#else // Linux
if (affinity > 0)
{
cpu_set_t mask;
CPU_ZERO(&mask);
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
if (affinity & (1 << i))
CPU_SET(i, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
else
{
CPU_ZERO(&mask);
sched_getaffinity(0, sizeof(mask), &mask);
TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
}
}
if (highPriority)
{
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno));
else
TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0));
}
#endif
#endif
}
void KeepDatabaseAliveHandler(const boost::system::error_code& error)
{
if (!error)
{
TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
LoginDatabase.KeepAlive();
_dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
}
}
/// Print out the usage string for this program on the console.
void usage(const char* prog)
{
TC_LOG_INFO("server.authserver", "Usage: \n %s [<options>]\n"
" -c config_file use config_file as configuration file\n\r",
prog);
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PROCESSPRIO_H
#define _PROCESSPRIO_H
#include "Configuration/Config.h"
#ifdef __linux__
#include <sched.h>
#include <sys/resource.h>
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
#endif
void SetProcessPriority(const std::string logChannel)
{
#if defined(_WIN32) || defined(__linux__)
///- Handle affinity for multiple processors and process priority
uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0);
bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false);
#ifdef _WIN32 // Windows
HANDLE hProcess = GetCurrentProcess();
if (affinity > 0)
{
ULONG_PTR appAff;
ULONG_PTR sysAff;
if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
{
// remove non accessible processors
ULONG_PTR currentAffinity = affinity & appAff;
if (!currentAffinity)
TC_LOG_ERROR(logChannel, "Processors marked in UseProcessors bitmask (hex) %x are not accessible. Accessible processors bitmask (hex): %x", affinity, appAff);
else if (SetProcessAffinityMask(hProcess, currentAffinity))
TC_LOG_INFO(logChannel, "Using processors (bitmask, hex): %x", currentAffinity);
else
TC_LOG_ERROR(logChannel, "Can't set used processors (hex): %x", currentAffinity);
}
}
if (highPriority)
{
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
TC_LOG_INFO(logChannel, "Process priority class set to HIGH");
else
TC_LOG_ERROR(logChannel, "Can't set process priority class.");
}
#else // Linux
if (affinity > 0)
{
cpu_set_t mask;
CPU_ZERO(&mask);
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
if (affinity & (1 << i))
CPU_SET(i, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
TC_LOG_ERROR(logChannel, "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
else
{
CPU_ZERO(&mask);
sched_getaffinity(0, sizeof(mask), &mask);
TC_LOG_INFO(logChannel, "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
}
}
if (highPriority)
{
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
TC_LOG_ERROR(logChannel, "Can't set process priority class, error: %s", strerror(errno));
else
TC_LOG_INFO(logChannel, "Process priority class set to %i", getpriority(PRIO_PROCESS, 0));
}
#endif
#endif
}
#endif

View File

@@ -11,7 +11,6 @@
file(GLOB_RECURSE sources_CommandLine CommandLine/*.cpp CommandLine/*.h)
file(GLOB_RECURSE sources_RemoteAccess RemoteAccess/*.cpp RemoteAccess/*.h)
file(GLOB_RECURSE sources_TCSoap TCSoap/*.cpp TCSoap/*.h)
file(GLOB_RECURSE sources_WorldThread WorldThread/*.cpp WorldThread/*.h)
file(GLOB sources_localdir *.cpp *.h)
if (USE_COREPCH)
@@ -24,7 +23,6 @@ set(worldserver_SRCS
${sources_CommandLine}
${sources_RemoteAccess}
${sources_TCSoap}
${sources_WorldThread}
${sources_localdir}
)
@@ -138,7 +136,6 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/CommandLine
${CMAKE_CURRENT_SOURCE_DIR}/RemoteAccess
${CMAKE_CURRENT_SOURCE_DIR}/TCSoap
${CMAKE_CURRENT_SOURCE_DIR}/WorldThread
${ACE_INCLUDE_DIR}
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}

View File

@@ -22,17 +22,30 @@
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <boost/asio/io_service.hpp>
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "DatabaseEnv.h"
#include "AsyncAcceptor.h"
#include "RASession.h"
#include "Configuration/Config.h"
#include "OpenSSLCrypto.h"
#include "ProcessPriority.h"
#include "BigNumber.h"
#include "RealmList.h"
#include "World.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "WorldSocketMgr.h"
#include "OutdoorPvP/OutdoorPvPMgr.h"
#include "BattlegroundMgr.h"
#include "TCSoap.h"
#include "CliRunnable.h"
#include "SystemConfig.h"
#include "Log.h"
#include "Master.h"
#ifndef _TRINITY_CORE_CONFIG
# define _TRINITY_CORE_CONFIG "worldserver.conf"
#endif
#define TRINITY_CORE_CONFIG "worldserver.conf"
#define WORLD_SLEEP_CONST 50
#ifdef _WIN32
#include "ServiceWin32.h"
@@ -48,31 +61,26 @@ char serviceDescription[] = "TrinityCore World of Warcraft emulator world servic
int m_ServiceStatus = -1;
#endif
boost::asio::io_service _ioService;
WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database
CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database
LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database
uint32 realmID; ///< Id of the realm
/// Print out the usage string for this program on the console.
void usage(const char* prog)
{
printf("Usage:\n");
printf(" %s [<options>]\n", prog);
printf(" -c config_file use config_file as configuration file\n");
#ifdef _WIN32
printf(" Running as service functions:\n");
printf(" --service run as service\n");
printf(" -s install install service\n");
printf(" -s uninstall uninstall service\n");
#endif
}
void usage(const char* prog);
void SignalHandler(const boost::system::error_code& error, int signalNumber);
void FreezeDetectorThread(uint32 delayTime);
AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService);
bool StartDB();
void StopDB();
void WorldUpdateLoop();
void ClearOnlineAccounts();
/// Launch the Trinity server
extern int main(int argc, char** argv)
{
///- Command line parsing to get the configuration file name
char const* cfg_file = _TRINITY_CORE_CONFIG;
char const* cfg_file = TRINITY_CORE_CONFIG;
int c = 1;
while (c < argc)
{
@@ -131,21 +139,442 @@ extern int main(int argc, char** argv)
return 1;
}
TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION);
TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n");
TC_LOG_INFO("server.worldserver", " ______ __");
TC_LOG_INFO("server.worldserver", "/\\__ _\\ __ __/\\ \\__");
TC_LOG_INFO("server.worldserver", "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __");
TC_LOG_INFO("server.worldserver", " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\");
TC_LOG_INFO("server.worldserver", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\");
TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\");
TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\");
TC_LOG_INFO("server.worldserver", " C O R E /\\___/");
TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n");
TC_LOG_INFO("server.worldserver", "Using configuration file %s.", cfg_file);
TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
TC_LOG_INFO("server.worldserver", "Using Boost version: %s", BOOST_LIB_VERSION);
TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
///- and run the 'Master'
/// @todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd?
int ret = sMaster->Run();
OpenSSLCrypto::threadsSetup();
BigNumber seed1;
seed1.SetRand(16 * 8);
/// worldserver PID file creation
std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
if (!pidFile.empty())
{
if (uint32 pid = CreatePIDFile(pidFile))
TC_LOG_INFO("server.worldserver", "Daemon PID: %u\n", pid);
else
{
TC_LOG_ERROR("server.worldserver", "Cannot create PID file %s.\n", pidFile.c_str());
return 1;
}
}
// Set signal handlers (this must be done before starting io_service threads, because otherwise they would unblock and exit)
boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
signals.async_wait(SignalHandler);
// Start the Boost based thread pool
int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1);
std::vector<std::thread> threadPool;
if (numThreads < 1)
numThreads = 1;
for (int i = 0; i < numThreads; ++i)
threadPool.push_back(std::thread(boost::bind(&boost::asio::io_service::run, &_ioService)));
// Set process priority according to configuration settings
SetProcessPriority("server.worldserver");
// Start the databases
if (!StartDB())
return 1;
// Set server offline (not connectable)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID);
// Initialize the World
sWorld->SetInitialWorldSettings();
// Launch CliRunnable thread
std::thread* cliThread = nullptr;
#ifdef _WIN32
if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
#else
if (sConfigMgr->GetBoolDefault("Console.Enable", true))
#endif
{
cliThread = new std::thread(CliThread);
}
// Start the Remote Access port (acceptor) if enabled
AsyncAcceptor<RASession>* raAcceptor = nullptr;
if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
raAcceptor = StartRaSocketAcceptor(_ioService);
// Start soap serving thread if enabled
std::thread* soapThread = nullptr;
if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
{
soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878)));
}
// Start up freeze catcher thread
std::thread* freezeDetectorThread = nullptr;
if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0))
freezeDetectorThread = new std::thread(FreezeDetectorThread, freezeDelay);
// Launch the worldserver listener socket
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1)
{
TC_LOG_ERROR("server.worldserver", "Failed to start network");
return ERROR_EXIT_CODE;
}
// Set server online (allow connecting now)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID);
TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION);
sScriptMgr->OnStartup();
WorldUpdateLoop();
// Shutdown starts here
_ioService.stop();
for (auto& thread : threadPool)
{
thread.join();
}
sScriptMgr->OnShutdown();
sWorld->KickAll(); // save and kick all players
sWorld->UpdateSessions(1); // real players unload required UpdateSessions call
// unload battleground templates before different singletons destroyed
sBattlegroundMgr->DeleteAllBattlegrounds();
sWorldSocketMgr->StopNetwork();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
sScriptMgr->Unload();
sOutdoorPvPMgr->Die();
// set server offline
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID);
// Clean up threads if any
if (soapThread != nullptr)
{
soapThread->join();
delete soapThread;
}
if (raAcceptor != nullptr)
delete raAcceptor;
///- Clean database before leaving
ClearOnlineAccounts();
StopDB();
TC_LOG_INFO("server.worldserver", "Halting process...");
if (cliThread != nullptr)
{
#ifdef _WIN32
// this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API)
//_exit(1);
// send keyboard input to safely unblock the CLI thread
INPUT_RECORD b[4];
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
b[0].EventType = KEY_EVENT;
b[0].Event.KeyEvent.bKeyDown = TRUE;
b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
b[0].Event.KeyEvent.wRepeatCount = 1;
b[1].EventType = KEY_EVENT;
b[1].Event.KeyEvent.bKeyDown = FALSE;
b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
b[1].Event.KeyEvent.wRepeatCount = 1;
b[2].EventType = KEY_EVENT;
b[2].Event.KeyEvent.bKeyDown = TRUE;
b[2].Event.KeyEvent.dwControlKeyState = 0;
b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
b[2].Event.KeyEvent.wRepeatCount = 1;
b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
b[3].EventType = KEY_EVENT;
b[3].Event.KeyEvent.bKeyDown = FALSE;
b[3].Event.KeyEvent.dwControlKeyState = 0;
b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
b[3].Event.KeyEvent.wRepeatCount = 1;
DWORD numb;
WriteConsoleInput(hStdIn, b, 4, &numb);
cliThread->join();
#endif
delete cliThread;
}
delete freezeDetectorThread;
OpenSSLCrypto::threadsCleanup();
// at sMaster return function exist with codes
// 0 - normal shutdown
// 1 - shutdown at error
// 2 - restart command used, this code can be used by restarter for restart Trinityd
return ret;
return World::GetExitCode();
}
void WorldUpdateLoop()
{
uint32 realCurrTime = 0;
uint32 realPrevTime = getMSTime();
uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST
///- While we have not World::m_stopEvent, update the world
while (!World::IsStopped())
{
++World::m_worldLoopCounter;
realCurrTime = getMSTime();
uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
sWorld->Update(diff);
realPrevTime = realCurrTime;
// diff (D0) include time of previous sleep (d0) + tick time (t0)
// we want that next d1 + t1 == WORLD_SLEEP_CONST
// we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
// d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
if (diff <= WORLD_SLEEP_CONST + prevSleepTime)
{
prevSleepTime = WORLD_SLEEP_CONST + prevSleepTime - diff;
std::this_thread::sleep_for(std::chrono::milliseconds(prevSleepTime));
}
else
prevSleepTime = 0;
#ifdef _WIN32
if (m_ServiceStatus == 0)
World::StopNow(SHUTDOWN_EXIT_CODE);
while (m_ServiceStatus == 2)
Sleep(1000);
#endif
}
}
/// Print out the usage string for this program on the console.
void usage(const char* prog)
{
printf("Usage:\n");
printf(" %s [<options>]\n", prog);
printf(" -c config_file use config_file as configuration file\n");
#ifdef _WIN32
printf(" Running as service functions:\n");
printf(" --service run as service\n");
printf(" -s install install service\n");
printf(" -s uninstall uninstall service\n");
#endif
}
void SignalHandler(const boost::system::error_code& error, int signalNumber)
{
if (!error)
{
switch (signalNumber)
{
case SIGINT:
case SIGTERM:
World::StopNow(SHUTDOWN_EXIT_CODE);
break;
}
}
}
void FreezeDetectorThread(uint32 delayTime)
{
if (!delayTime)
return;
TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", delayTime / 1000);
uint32 loops = 0;
uint32 lastChange = 0;
while (!World::IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
uint32 curtime = getMSTime();
// normal work
uint32 worldLoopCounter = World::m_worldLoopCounter;
if (loops != worldLoopCounter)
{
lastChange = curtime;
loops = worldLoopCounter;
}
// possible freeze
else if (getMSTimeDiff(lastChange, curtime) > delayTime)
{
TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!");
ASSERT(false);
}
}
TC_LOG_INFO("server.worldserver", "Anti-freeze thread exiting without problems.");
}
AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService)
{
uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
return new AsyncAcceptor<RASession>(ioService, raListener, raPort);
}
/// Initialize connection to the databases
bool StartDB()
{
MySQL::Library_Init();
std::string dbString;
uint8 asyncThreads, synchThreads;
dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", "");
if (dbString.empty())
{
TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file");
return false;
}
asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1));
///- Initialize the world database
if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads))
{
TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str());
return false;
}
///- Get character database info from configuration file
dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", "");
if (dbString.empty())
{
TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file");
return false;
}
asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2));
///- Initialize the Character database
if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads))
{
TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str());
return false;
}
///- Get login database info from configuration file
dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
if (dbString.empty())
{
TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file");
return false;
}
asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1));
///- Initialise the login database
if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads))
{
TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str());
return false;
}
///- Get the realm Id from the configuration file
realmID = sConfigMgr->GetIntDefault("RealmID", 0);
if (!realmID)
{
TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
return false;
}
TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realmID);
///- Clean the database before starting
ClearOnlineAccounts();
///- Insert version info into DB
WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query
sWorld->LoadDBVersion();
TC_LOG_INFO("server.worldserver", "Using World DB: %s", sWorld->GetDBVersion());
return true;
}
void StopDB()
{
CharacterDatabase.Close();
WorldDatabase.Close();
LoginDatabase.Close();
MySQL::Library_End();
}
/// Clear 'online' status for all accounts with characters in this realm
void ClearOnlineAccounts()
{
// Reset online status for all accounts with characters on the current realm
LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realmID);
// Reset online status for all characters
CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
// Battleground instance ids reset at server restart
CharacterDatabase.DirectExecute("UPDATE character_battleground_data SET instanceId = 0");
}
/// @}

View File

@@ -1,479 +0,0 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/** \file
\ingroup Trinityd
*/
#include <thread>
#include "Master.h"
#include "SystemConfig.h"
#include "World.h"
#include "WorldRunnable.h"
#include "WorldSocket.h"
#include "WorldSocketMgr.h"
#include "Configuration/Config.h"
#include "Database/DatabaseEnv.h"
#include "Database/DatabaseWorkerPool.h"
#include "CliRunnable.h"
#include "Log.h"
#include "TCSoap.h"
#include "Timer.h"
#include "Util.h"
#include "RealmList.h"
#include "BigNumber.h"
#include "OpenSSLCrypto.h"
#include "AsyncAcceptor.h"
#ifdef _WIN32
#include "ServiceWin32.h"
extern int m_ServiceStatus;
#endif
#ifdef __linux__
#include <sched.h>
#include <sys/resource.h>
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
#endif
boost::asio::io_service _ioService;
void SignalHandler(const boost::system::error_code& error, int signalNumber)
{
if (!error)
{
switch (signalNumber)
{
case SIGINT:
case SIGTERM:
_ioService.stop();
break;
}
}
}
void FreezeDetectorThread(uint32 delayTime)
{
if (!delayTime)
return;
TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", delayTime / 1000);
uint32 loops = 0;
uint32 lastChange = 0;
while (!World::IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
uint32 curtime = getMSTime();
// normal work
uint32 worldLoopCounter = World::m_worldLoopCounter;
if (loops != worldLoopCounter)
{
lastChange = curtime;
loops = worldLoopCounter;
}
// possible freeze
else if (getMSTimeDiff(lastChange, curtime) > delayTime)
{
TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!");
ASSERT(false);
}
}
TC_LOG_INFO("server.worldserver", "Anti-freeze thread exiting without problems.");
}
/// Main function
int Master::Run()
{
OpenSSLCrypto::threadsSetup();
BigNumber seed1;
seed1.SetRand(16 * 8);
TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION);
TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n");
TC_LOG_INFO("server.worldserver", " ______ __");
TC_LOG_INFO("server.worldserver", "/\\__ _\\ __ __/\\ \\__");
TC_LOG_INFO("server.worldserver", "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __");
TC_LOG_INFO("server.worldserver", " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\");
TC_LOG_INFO("server.worldserver", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\");
TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\");
TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\");
TC_LOG_INFO("server.worldserver", " C O R E /\\___/");
TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n");
/// worldserver PID file creation
std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
if (!pidFile.empty())
{
if (uint32 pid = CreatePIDFile(pidFile))
TC_LOG_INFO("server.worldserver", "Daemon PID: %u\n", pid);
else
{
TC_LOG_ERROR("server.worldserver", "Cannot create PID file %s.\n", pidFile.c_str());
return 1;
}
}
///- Start the databases
if (!_StartDB())
return 1;
// set server offline (not connectable)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID);
///- Initialize the World
sWorld->SetInitialWorldSettings();
// Set signal handlers
boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
signals.async_wait(SignalHandler);
///- Launch WorldRunnable thread
std::thread worldThread(WorldThread, std::ref(_ioService));
std::thread* cliThread = nullptr;
#ifdef _WIN32
if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
#else
if (sConfigMgr->GetBoolDefault("Console.Enable", true))
#endif
{
///- Launch CliRunnable thread
cliThread = new std::thread(CliThread);
}
AsyncAcceptor<RASession>* raAcceptor = nullptr;
if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
raAcceptor = StartRaSocketAcceptor(_ioService);
#if defined(_WIN32) || defined(__linux__)
///- Handle affinity for multiple processors and process priority
uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0);
bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false);
#ifdef _WIN32 // Windows
HANDLE hProcess = GetCurrentProcess();
if (affinity > 0)
{
ULONG_PTR appAff;
ULONG_PTR sysAff;
if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
{
ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors
if (!currentAffinity)
TC_LOG_ERROR("server.worldserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff);
else if (SetProcessAffinityMask(hProcess, currentAffinity))
TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %x", currentAffinity);
else
TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x", currentAffinity);
}
}
if (highPriority)
{
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
TC_LOG_INFO("server.worldserver", "worldserver process priority class set to HIGH");
else
TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class.");
}
#else // Linux
if (affinity > 0)
{
cpu_set_t mask;
CPU_ZERO(&mask);
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
if (affinity & (1 << i))
CPU_SET(i, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
else
{
CPU_ZERO(&mask);
sched_getaffinity(0, sizeof(mask), &mask);
TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
}
}
if (highPriority)
{
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class, error: %s", strerror(errno));
else
TC_LOG_INFO("server.worldserver", "worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0));
}
#endif
#endif
//Start soap serving thread
std::thread* soapThread = nullptr;
if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
{
soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878)));
}
std::thread* freezeDetectorThread = nullptr;
///- Start up freeze catcher thread
if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0))
freezeDetectorThread = new std::thread(FreezeDetectorThread, freezeDelay);
///- Launch the world listener socket
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1)
{
TC_LOG_ERROR("server.worldserver", "Failed to start network");
World::StopNow(ERROR_EXIT_CODE);
// go down and shutdown the server
}
// set server online (allow connecting now)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID);
TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION);
_ioService.run();
// when the main thread closes the singletons get unloaded
// since worldrunnable uses them, it will crash if unloaded after master
worldThread.join();
if (soapThread != nullptr)
{
soapThread->join();
delete soapThread;
}
if (raAcceptor != nullptr)
delete raAcceptor;
// set server offline
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID);
///- Clean database before leaving
ClearOnlineAccounts();
_StopDB();
TC_LOG_INFO("server.worldserver", "Halting process...");
if (cliThread != nullptr)
{
#ifdef _WIN32
// this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API)
//_exit(1);
// send keyboard input to safely unblock the CLI thread
INPUT_RECORD b[4];
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
b[0].EventType = KEY_EVENT;
b[0].Event.KeyEvent.bKeyDown = TRUE;
b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
b[0].Event.KeyEvent.wRepeatCount = 1;
b[1].EventType = KEY_EVENT;
b[1].Event.KeyEvent.bKeyDown = FALSE;
b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
b[1].Event.KeyEvent.wRepeatCount = 1;
b[2].EventType = KEY_EVENT;
b[2].Event.KeyEvent.bKeyDown = TRUE;
b[2].Event.KeyEvent.dwControlKeyState = 0;
b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
b[2].Event.KeyEvent.wRepeatCount = 1;
b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
b[3].EventType = KEY_EVENT;
b[3].Event.KeyEvent.bKeyDown = FALSE;
b[3].Event.KeyEvent.dwControlKeyState = 0;
b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
b[3].Event.KeyEvent.wRepeatCount = 1;
DWORD numb;
WriteConsoleInput(hStdIn, b, 4, &numb);
cliThread->join();
#endif
delete cliThread;
}
delete freezeDetectorThread;
// for some unknown reason, unloading scripts here and not in worldrunnable
// fixes a memory leak related to detaching threads from the module
//UnloadScriptingModule();
OpenSSLCrypto::threadsCleanup();
// Exit the process with specified return value
return World::GetExitCode();
}
/// Initialize connection to the databases
bool Master::_StartDB()
{
MySQL::Library_Init();
std::string dbString;
uint8 asyncThreads, synchThreads;
dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", "");
if (dbString.empty())
{
TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file");
return false;
}
asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1));
///- Initialize the world database
if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads))
{
TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str());
return false;
}
///- Get character database info from configuration file
dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", "");
if (dbString.empty())
{
TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file");
return false;
}
asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2));
///- Initialize the Character database
if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads))
{
TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str());
return false;
}
///- Get login database info from configuration file
dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
if (dbString.empty())
{
TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file");
return false;
}
asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1));
///- Initialise the login database
if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads))
{
TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str());
return false;
}
///- Get the realm Id from the configuration file
realmID = sConfigMgr->GetIntDefault("RealmID", 0);
if (!realmID)
{
TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
return false;
}
TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realmID);
///- Clean the database before starting
ClearOnlineAccounts();
///- Insert version info into DB
WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query
sWorld->LoadDBVersion();
TC_LOG_INFO("server.worldserver", "Using World DB: %s", sWorld->GetDBVersion());
return true;
}
void Master::_StopDB()
{
CharacterDatabase.Close();
WorldDatabase.Close();
LoginDatabase.Close();
MySQL::Library_End();
}
/// Clear 'online' status for all accounts with characters in this realm
void Master::ClearOnlineAccounts()
{
// Reset online status for all accounts with characters on the current realm
LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realmID);
// Reset online status for all characters
CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
// Battleground instance ids reset at server restart
CharacterDatabase.DirectExecute("UPDATE character_battleground_data SET instanceId = 0");
}
AsyncAcceptor<RASession>* Master::StartRaSocketAcceptor(boost::asio::io_service& ioService)
{
uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
return new AsyncAcceptor<RASession>(ioService, raListener, raPort);
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef _MASTER_H
#define _MASTER_H
#include <boost/asio/io_service.hpp>
#include "Common.h"
#include "RASession.h"
template<typename T>
class AsyncAcceptor;
/// Start the server
class Master
{
public:
static Master* instance()
{
static Master* instance = new Master();
return instance;
}
int Run();
private:
bool _StartDB();
void _StopDB();
void ClearOnlineAccounts();
AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService);
};
#define sMaster Master::instance()
#endif
/// @}

View File

@@ -1,103 +0,0 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/** \file
\ingroup Trinityd
*/
#include <thread>
#include "Common.h"
#include "ObjectAccessor.h"
#include "World.h"
#include "WorldSocketMgr.h"
#include "Database/DatabaseEnv.h"
#include "ScriptMgr.h"
#include "BattlegroundMgr.h"
#include "MapManager.h"
#include "Timer.h"
#include "WorldRunnable.h"
#include "OutdoorPvPMgr.h"
#define WORLD_SLEEP_CONST 50
#ifdef _WIN32
#include "ServiceWin32.h"
extern int m_ServiceStatus;
#endif
/// Heartbeat for the World
void WorldThread(boost::asio::io_service& ioService)
{
uint32 realCurrTime = 0;
uint32 realPrevTime = getMSTime();
uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST
sScriptMgr->OnStartup();
///- While we have not World::m_stopEvent, update the world
while (!World::IsStopped())
{
++World::m_worldLoopCounter;
realCurrTime = getMSTime();
uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
sWorld->Update( diff );
realPrevTime = realCurrTime;
// diff (D0) include time of previous sleep (d0) + tick time (t0)
// we want that next d1 + t1 == WORLD_SLEEP_CONST
// we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
// d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
if (diff <= WORLD_SLEEP_CONST+prevSleepTime)
{
prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff;
std::this_thread::sleep_for(std::chrono::milliseconds(prevSleepTime));
}
else
prevSleepTime = 0;
#ifdef _WIN32
if (m_ServiceStatus == 0)
World::StopNow(SHUTDOWN_EXIT_CODE);
while (m_ServiceStatus == 2)
Sleep(1000);
#endif
}
ioService.stop();
sScriptMgr->OnShutdown();
sWorld->KickAll(); // save and kick all players
sWorld->UpdateSessions( 1 ); // real players unload required UpdateSessions call
// unload battleground templates before different singletons destroyed
sBattlegroundMgr->DeleteAllBattlegrounds();
sWorldSocketMgr->StopNetwork();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
sScriptMgr->Unload();
sOutdoorPvPMgr->Die();
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef __WORLDRUNNABLE_H
#define __WORLDRUNNABLE_H
#include <boost/asio/io_service.hpp>
void WorldThread(boost::asio::io_service& ioService);
#endif
/// @}

View File

@@ -143,6 +143,14 @@ WorldServerPort = 8085
BindIP = "0.0.0.0"
#
# ThreadPool
# Description: Number of threads to be used for the global thread pool
# The thread pool is currently used for the signal handler and remote access
# Default: 1
ThreadPool = 1
#
###################################################################################################
@@ -161,7 +169,8 @@ UseProcessors = 0
#
# ProcessPriority
# Description: Process priority setting for Windows and Linux based systems.
# Details: On Linux, a nice value of -15 is used. (requires superuser). On Windows, process is set to HIGH class.
# Details: On Linux, a nice value of -15 is used. (requires superuser).
# On Windows, process is set to HIGH class.
# Default: 0 - (Normal)
# 1 - (High)
@@ -1069,7 +1078,8 @@ Account.PasswordChangeSecurity = 0
#
# BirthdayTime
# Description: Set to date of project's birth in UNIX time. By default the date when TrinityCore was started (Thu Oct 2, 2008)
# Description: Set to date of project's birth in UNIX time. By default the date when
# TrinityCore was started (Thu Oct 2, 2008)
# Default: 1222964635
#
#
@@ -2627,8 +2637,10 @@ UI.ShowQuestLevelsInDialogs = 0
# 1 - Prefix Timestamp to the text
# 2 - Prefix Log Level to the text
# 4 - Prefix Log Filter type to the text
# 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS (Only used with Type = 2)
# 16 - Make a backup of existing file before overwrite (Only used with Mode = w)
# 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS
# (Only used with Type = 2)
# 16 - Make a backup of existing file before overwrite
# (Only used with Mode = w)
#
# Colors (read as optional1 if Type = Console)
# Format: "fatal error warn info debug trace"
@@ -2744,7 +2756,8 @@ Log.Async.Enable = 0
#
# Allow.IP.Based.Action.Logging
# Description: Logs actions, e.g. account login and logout to name a few, based on IP of current session.
# Description: Logs actions, e.g. account login and logout to name a few, based on IP of
# current session.
# Default: 0 - (Disabled)
# 1 - (Enabled)