File: errorhandler.cpp

package info (click to toggle)
spring 104.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 47,512 kB
  • sloc: cpp: 391,093; ansic: 79,943; python: 12,356; java: 12,201; awk: 5,889; sh: 1,826; xml: 655; makefile: 486; perl: 405; php: 211; objc: 194; sed: 2
file content (100 lines) | stat: -rw-r--r-- 2,771 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

/**
 * @brief error messages
 * Error handling based on platform.
 */


#include "errorhandler.h"

#include <string>
#include <functional>

#include "System/Log/ILog.h"
#include "System/Log/LogSinkHandler.h"
#include "System/Threading/SpringThreading.h"

#if !defined(DEDICATED)
	#include "System/SpringApp.h"
	#include "System/Platform/Threading.h"
#endif
#if !defined(DEDICATED) && !defined(HEADLESS)
	#include "System/Platform/MessageBox.h"
#endif
#ifdef DEDICATED
	#include "Net/GameServer.h"
	#include "System/SafeUtil.h"
#endif


static void ExitSpringProcessAux(bool waitForExit, bool exitSuccess)
{
	// wait 10 seconds before forcing the kill
	for (unsigned int n = 0; (waitForExit && n < 10); ++n) {
		spring::this_thread::sleep_for(std::chrono::seconds(1));
	}

	logSinkHandler.SetSinking(false);

#ifdef _MSC_VER
	if (!exitSuccess)
		TerminateProcess(GetCurrentProcess(), EXIT_FAILURE);
#endif

	exit(EXIT_FAILURE);
}


#ifdef DEDICATED
static void ExitSpringProcess(const std::string& msg, const std::string& caption, unsigned int flags)
{
	LOG_L(L_ERROR, "[%s] errorMsg=\"%s\" msgCaption=\"%s\"", __func__, msg.c_str(), caption.c_str());

	spring::SafeDelete(gameServer);
	ExitSpringProcessAux(false, true);
}

#else

static void ExitSpringProcess(const std::string& msg, const std::string& caption, unsigned int flags)
{
	LOG_L(L_ERROR, "[%s] errorMsg=\"%s\" msgCaption=\"%s\" mainThread=%d", __func__, msg.c_str(), caption.c_str(), Threading::IsMainThread());

	switch (SpringApp::PostKill(Threading::Error(caption, msg, flags))) {
		case -1: {
			// main thread; either gets to ESPA first and cleans up our process or exit is forced by this
			std::function<void()> forcedExitFunc = [&]() { ExitSpringProcessAux(true, false); };
			spring::thread forcedExitThread = std::move(spring::thread(forcedExitFunc));

			// .join can (very rarely) throw a no-such-process exception if it runs in parallel with exit
			assert(forcedExitThread.joinable());
			forcedExitThread.detach();

			SpringApp::Kill(false);
		} break;
		case 0: {         } break; // thread failed to post, ESPA
		case 1: { return; } break; // thread posted successfully
	}

	ExitSpringProcessAux(false, false);
}
#endif


void ErrorMessageBox(const std::string& msg, const std::string& caption, unsigned int flags)
{
	#if (!defined(DEDICATED))
	// the thread that throws up this message-box will be blocked
	// until it is clicked away which can cause spurious detected
	// hangs, so deregister it here (by passing an empty error)
	SpringApp::PostKill({});
	#endif

	#if (!defined(DEDICATED) && !defined(HEADLESS))
	Platform::MsgBox(msg, caption, flags);
	#endif

	ExitSpringProcess(msg, caption, flags);
}