OregonCore  revision be9e804-git
Your Favourite TBC server
Master Class Reference

#include <Master.h>

Public Member Functions

 Master ()
 
 ~Master ()
 
int Run (bool runTests)
 
bool RunRegressionTests ()
 

Static Public Attributes

static volatile uint32 m_masterLoopCounter = 0
 

Private Member Functions

void _StartDB ()
 
void _HookSignals ()
 
void _UnhookSignals ()
 
void MainLoop ()
 
void clearOnlineAccounts ()
 

Static Private Member Functions

static void _OnSignal (int s)
 

Detailed Description

Definition at line 26 of file Master.h.

Constructor & Destructor Documentation

Master::Master ( )

Definition at line 99 of file Master.cpp.

100 {
101 }
Master::~Master ( )

Definition at line 103 of file Master.cpp.

104 {
105 }

Member Function Documentation

void Master::_HookSignals ( )
private

Definition at line 409 of file Master.cpp.

410 {
411  signal(SIGINT, _OnSignal);
412  signal(SIGTERM, _OnSignal);
413  #ifdef _WIN32
414  signal(SIGBREAK, _OnSignal);
415  #endif
416 }
static void _OnSignal(int s)
Definition: Master.cpp:390
void Master::_OnSignal ( int  s)
staticprivate

Definition at line 390 of file Master.cpp.

References SHUTDOWN_EXIT_CODE, and World::StopNow().

391 {
392  switch (s)
393  {
394  case SIGINT:
396  break;
397  case SIGTERM:
398  #ifdef _WIN32
399  case SIGBREAK:
400  #endif
402  break;
403  }
404 
405  signal(s, _OnSignal);
406 }
static void _OnSignal(int s)
Definition: Master.cpp:390
static void StopNow(uint8 exitcode)
Definition: World.h:632
void Master::_StartDB ( )
private

Definition at line 332 of file Master.cpp.

References _FULLVERSION, CharacterDatabase, Database::Initialize(), LoginDatabase, Database::PExecute(), realmID, sConfig, sConsole, sLog, sWorld, and WorldDatabase.

333 {
334  sConsole.SetLoadingLabel("Connecting to databases...");
335 
336  // Get world database info from configuration file
337  std::string dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", "");
338  if (dbstring.empty())
339  sLog.outFatal("World database not specified in configuration file");
340 
341  // Initialise the world database
342  if (!WorldDatabase.Initialize(dbstring.c_str()))
343  sLog.outFatal("Cannot connect to world database %s", dbstring.c_str());
344 
345  // Get character database info from configuration file
346  dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", "");
347  if (dbstring.empty())
348  sLog.outFatal("Character database not specified in configuration file");
349 
350  // Initialise the Character database
351  if (!CharacterDatabase.Initialize(dbstring.c_str()))
352  sLog.outFatal("Cannot connect to Character database %s", dbstring.c_str());
353 
354  // Get login database info from configuration file
355  dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", "");
356  if (dbstring.empty())
357  sLog.outFatal("Login database not specified in configuration file");
358 
359  // Initialise the login database
360  if (!LoginDatabase.Initialize(dbstring.c_str()))
361  sLog.outFatal("Cannot connect to login database %s", dbstring.c_str());
362 
363  // Get the realm Id from the configuration file
364  realmID = sConfig.GetIntDefault("RealmID", 0);
365  if (!realmID)
366  sLog.outFatal("Realm ID not defined in configuration file");
367 
368  sLog.outString("Realm running as realm ID %d", realmID);
369 
370  // Clean the database before starting
372 
373  // Insert version info into DB
374  WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _REVISION);
375 
376  sWorld.LoadDBVersion();
377 
378  sLog.outString("Using World DB: %s", sWorld.GetDBVersion());
379 }
#define sConfig
Definition: Config.h:52
DatabaseType WorldDatabase
Accessor to the world database.
Definition: Main.cpp:53
#define sConsole
Definition: Console.h:99
#define sLog
Log class singleton.
Definition: Log.h:187
void clearOnlineAccounts()
Definition: Master.cpp:382
DatabaseType LoginDatabase
Accessor to the realm/login database.
Definition: Main.cpp:55
bool Initialize(const char *infoString)
Definition: Database.cpp:75
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
#define _FULLVERSION
Definition: SystemConfig.h:40
uint32 realmID
Id of the realm.
Definition: Main.cpp:57
#define sWorld
Definition: World.h:860
DatabaseType CharacterDatabase
Accessor to the character database.
Definition: Main.cpp:54
void Master::_UnhookSignals ( )
private

Definition at line 419 of file Master.cpp.

420 {
421  signal(SIGINT, 0);
422  signal(SIGTERM, 0);
423  #ifdef _WIN32
424  signal(SIGBREAK, 0);
425  #endif
426 }
void Master::clearOnlineAccounts ( )
private

Definition at line 382 of file Master.cpp.

References CharacterDatabase, Database::Execute(), LoginDatabase, and Database::PExecute().

383 {
384  // Cleanup online status for characters hosted at current realm
385  LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE online<>0");
386  CharacterDatabase.Execute("UPDATE characters SET online = 0 WHERE online<>0");
387 }
bool Execute(const char *sql)
Definition: Database.cpp:420
DatabaseType LoginDatabase
Accessor to the realm/login database.
Definition: Main.cpp:55
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
DatabaseType CharacterDatabase
Accessor to the character database.
Definition: Main.cpp:54
void Master::MainLoop ( )
private

Definition at line 435 of file Master.cpp.

References getMSTime(), getMSTimeDiff(), World::IsStopped(), World::m_worldLoopCounter, ACE_Based::Thread::Sleep(), sWorld, and WORLD_SLEEP_CONST.

436 {
437  uint32 realCurrTime = 0;
438  uint32 realPrevTime = getMSTime();
439 
440  uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST
441 
442  // While we have not World::m_stopEvent, update the world
443  while (!World::IsStopped())
444  {
446  realCurrTime = getMSTime();
447 
448  uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
449 
450  sWorld.Update(diff);
451  realPrevTime = realCurrTime;
452 
453  // diff (D0) include time of previous sleep (d0) + tick time (t0)
454  // we want that next d1 + t1 == WORLD_SLEEP_CONST
455  // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
456  // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
457  if (diff <= WORLD_SLEEP_CONST + prevSleepTime)
458  {
459  prevSleepTime = WORLD_SLEEP_CONST + prevSleepTime - diff;
460  ACE_Based::Thread::Sleep(prevSleepTime);
461  }
462  else
463  prevSleepTime = 0;
464  }
465 }
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:78
uint32 getMSTime()
Definition: Timer.h:32
#define WORLD_SLEEP_CONST
Definition: Master.cpp:47
static bool IsStopped()
Definition: World.h:638
static void Sleep(unsigned long msecs)
Definition: Threading.cpp:237
static volatile uint32 m_worldLoopCounter
Definition: World.h:460
#define sWorld
Definition: World.h:860
ACE_UINT32 uint32
Definition: Define.h:71
int Master::Run ( bool  runTests)

Definition at line 108 of file Master.cpp.

References AcceptableClientBuildsListStr(), CharacterDatabase, CONFIG_PORT_WORLD, CreatePIDFile(), dup2, ERROR_EXIT_CODE, Database::escape_string(), FreezeDetectorRunnable::FreezeDetectorRunnable(), World::GetExitCode(), Database::HaltDelayThread(), ACE_Based::Highest, Oregon::Singleton< ObjectAccessor, Oregon::ClassLevelLockable< ObjectAccessor, ACE_Thread_Mutex > >::Instance(), Oregon::Singleton< MapManager, Oregon::ClassLevelLockable< MapManager, ACE_Thread_Mutex > >::Instance(), ACE_Based::Thread::kill(), LoginDatabase, Database::PExecute(), REALM_FLAG_OFFLINE, realmID, ObjectAccessor::SaveAllPlayers(), sBattlegroundMgr, sConfig, sConsole, FreezeDetectorRunnable::SetDelayTime(), OCSoapRunnable::setListenArguments(), ACE_Based::Thread::setPriority(), SHUTDOWN_EXIT_CODE, ACE_Based::Thread::Sleep(), sLog, World::StopNow(), sWorld, sWorldSocketMgr, Database::ThreadEnd(), Database::ThreadStart(), MapManager::UnloadAll(), ACE_Based::Thread::wait(), and WorldDatabase.

109 {
110  int defaultStderr = dup(2);
111 
112  if (sConfig.GetBoolDefault("Console.Enable", true))
113  sConsole.Initialize();
114  sConsole.SetLoading(true);
115  sConsole.DrawLogo();
116 
117  // worldd PID file creation
118  std::string pidfile = sConfig.GetStringDefault("PidFile", "");
119  if (!pidfile.empty())
120  {
121  uint32 pid = CreatePIDFile(pidfile);
122  if (!pid)
123  {
124  sLog.outError("Cannot create PID file %s.\n", pidfile.c_str());
125  return 1;
126  }
127 
128  sLog.outString("Daemon PID: %u\n", pid);
129  }
130 
131  // Start the databases
132  _StartDB();
133 
134  // Initialize the World
135  sWorld.SetInitialWorldSettings();
136 
137  // set realmbuilds depend on OregonCore expected builds, and set server online
138  std::string builds = AcceptableClientBuildsListStr();
140  LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID);
141 
142  sConsole.SetLoading(false);
143 
144  // Catch termination signals
145  _HookSignals();
146 
147  ACE_Based::Thread* cliThread = NULL;
148 
149  #ifdef _WIN32
150  if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
151  #else
152  if (sConfig.GetBoolDefault("Console.Enable", true))
153  #endif
154  {
155  // Launch CliRunnable thread
156  cliThread = new ACE_Based::Thread(new Console::CliRunnable);
157  }
158 
159  ACE_Based::Thread rar_thread(new RARunnable);
160 
161  // Handle affinity for multiple processors and process priority on Windows
162  #ifdef _WIN32
163  {
164  HANDLE hProcess = GetCurrentProcess();
165 
166  uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
167  if (Aff > 0)
168  {
169  ULONG_PTR appAff;
170  ULONG_PTR sysAff;
171 
172  if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
173  {
174  ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
175 
176  if (!curAff)
177  sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for OregonCore. Accessible processors bitmask (hex): %x", Aff, appAff);
178  else
179  {
180  if (SetProcessAffinityMask(hProcess, curAff))
181  sLog.outString("Using processors (bitmask, hex): %x", curAff);
182  else
183  sLog.outError("Can't set used processors (hex): %x", curAff);
184  }
185  }
186  sLog.outString();
187  }
188 
189  bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
190 
191  if (Prio)
192  {
193  if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
194  sLog.outString("OregonCore process priority class set to HIGH");
195  else
196  sLog.outError("ERROR: Can't set OregonCore process priority class.");
197  sLog.outString();
198  }
199  }
200  #endif
201 
202  // Start soap serving thread
203  ACE_Based::Thread* soap_thread = NULL;
204 
205  if (sConfig.GetBoolDefault("SOAP.Enabled", false))
206  {
207  OCSoapRunnable* runnable = new OCSoapRunnable();
208 
209  runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878));
210  soap_thread = new ACE_Based::Thread(runnable);
211  }
212 
213  //uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME);
214 
215  // Start up freeze catcher thread
216  ACE_Based::Thread* freeze_thread = NULL;
217  if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0))
218  {
220  fdr->SetDelayTime(freeze_delay * 1000);
221  freeze_thread = new ACE_Based::Thread(fdr);
222  freeze_thread->setPriority(ACE_Based::Highest);
223  }
224 
225  // Launch the world listener socket
226  uint16 wsport = sWorld.getConfig(CONFIG_PORT_WORLD);
227  std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0");
228 
229  if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1)
230  {
231  sLog.outError("Failed to start network");
233  // go down and shutdown the server
234  // give other threads a chance to start-up so we can shutdown them safely
236  }
237 
238  // ----------------------------------------------------------------------------------------------------------------
239  //
240 
241  // Init new SQL thread for the world database
242  WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough)
243  sWorld.InitResultQueue();
244 
245  // Run regression tests, then gracefully exit with particular exit code
246  if (runTests)
247  {
248  if (RunRegressionTests())
250  else
252  }
253 
254  // Run our World, we use main thread for this,
255  MainLoop();
256 
257  ObjectAccessor::Instance().SaveAllPlayers(); // save all players
258  sWorld.KickAll(); // kick all players
259  sWorld.UpdateSessions( 1 ); // real players unload required UpdateSessions call
260 
261  // unload battleground templates before different singletons destroyed
262  sBattlegroundMgr.DeleteAlllBattlegrounds();
263 
264  sWorldSocketMgr->StopNetwork();
265 
266  MapManager::Instance().UnloadAll(); // unload all grids (including locked in memory)
267 
268  // End the database thread
269  WorldDatabase.ThreadEnd(); // free mySQL thread resources
270 
271  //
272  // ----------------------------------------------------------------------------------------------------------------
273 
274  // Stop freeze protection before shutdown tasks
275  if (freeze_thread)
276  {
277  freeze_thread->kill(-1); // destroy
278  freeze_thread->wait();
279  delete freeze_thread;
280  }
281 
282  sWorldSocketMgr->Wait();
283 
284  // Stop soap thread
285  if (soap_thread)
286  {
287  soap_thread->wait();
288  delete soap_thread;
289  }
290 
291  // Set server offline in realmlist
292  LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID);
293 
294  // when the main thread closes the singletons get unloaded
295  // since MainLoop uses them, it will crash if unloaded after master
296  rar_thread.wait ();
297 
298  // Clean account database before leaving
300 
301  // Wait for delay threads to end
305 
306  sLog.outString("Halting process...");
307 
308  if (cliThread)
309  {
310  cliThread->kill(SIGINT);
311  cliThread->wait();
312  delete cliThread;
313  }
314 
315  // we've been messing up with stderr (if Console.Enable was set),
316  // so we need to restore it back, to prevent SIGPIPEs after restart
317  dup2(defaultStderr, 2);
318  close(defaultStderr);
319 
320  // Remove signal handling before leaving
321  _UnhookSignals();
322 
323  // for some unknown reason, unloading scripts here and not in MainLoop
324  // fixes a memory leak related to detaching threads from the module
325  //UnloadScriptingModule();
326 
327  // Exit the process with specified return value
328  return World::GetExitCode();
329 }
#define dup2
Definition: Common.h:136
#define sConfig
Definition: Config.h:52
#define sWorldSocketMgr
std::string AcceptableClientBuildsListStr()
Definition: DBCStores.cpp:168
DatabaseType WorldDatabase
Accessor to the world database.
Definition: Main.cpp:53
void ThreadEnd()
Definition: Database.cpp:196
#define sConsole
Definition: Console.h:99
#define sLog
Log class singleton.
Definition: Log.h:187
unsigned long escape_string(char *to, const char *from, unsigned long length)
Definition: Database.cpp:212
void clearOnlineAccounts()
Definition: Master.cpp:382
bool kill(int signal)
Definition: Threading.cpp:157
void SetDelayTime(uint32 t)
Definition: Master.cpp:63
static void Sleep(unsigned long msecs)
Definition: Threading.cpp:237
static uint8 GetExitCode()
Definition: World.h:628
DatabaseType LoginDatabase
Accessor to the realm/login database.
Definition: Main.cpp:55
void MainLoop()
Definition: Master.cpp:435
void setPriority(Priority type)
Definition: Threading.cpp:229
void ThreadStart()
Definition: Database.cpp:191
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
void UnloadAll()
Definition: MapManager.cpp:273
void HaltDelayThread()
Definition: Database.cpp:645
void _UnhookSignals()
Definition: Master.cpp:419
uint32 realmID
Id of the realm.
Definition: Main.cpp:57
#define sBattlegroundMgr
void setListenArguments(std::string host, uint16 port)
Definition: OCSoap.h:38
uint32 CreatePIDFile(const std::string &filename)
Definition: Util.cpp:203
void _HookSignals()
Definition: Master.cpp:409
void _StartDB()
Definition: Master.cpp:332
#define sWorld
Definition: World.h:860
bool RunRegressionTests()
Definition: Master.cpp:428
DatabaseType CharacterDatabase
Accessor to the character database.
Definition: Main.cpp:54
ACE_UINT16 uint16
Definition: Define.h:72
ACE_UINT32 uint32
Definition: Define.h:71
static void StopNow(uint8 exitcode)
Definition: World.h:632
bool Master::RunRegressionTests ( )

Definition at line 428 of file Master.cpp.

References RegressionTestSuite::RunAll().

429 {
430  RegressionTestSuite suite;
431  return suite.RunAll();
432 }

Member Data Documentation

volatile uint32 Master::m_masterLoopCounter = 0
static

Definition at line 32 of file Master.h.


The documentation for this class was generated from the following files: