summaryrefslogtreecommitdiffstats
path: root/src/OSSupport/ConsoleSignalHandler.h
blob: 23e63d5552cf6834a6a5b0b391c4674f21c2bc8e (plain) (blame)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

// ConsoleSignalHandler.h

// Intercepts signals for graceful CTRL-C (and others) handling.

// This file MUST NOT be included from anywhere other than main.cpp.





#include <csignal>





// Because SIG_DFL or SIG_IGN could be NULL instead of nullptr, we need to disable the Clang warning here:
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif

static void NonCtrlHandler(int a_Signal)
{
	LOGD("Terminate event raised from std::signal");

	switch (a_Signal)
	{
		case SIGSEGV:
		{
			PrintStackTrace();

			LOGERROR(
				"Failure report: \n\n"
				"  :(   | Cuberite has encountered an error and needs to close\n"
				"       | SIGSEGV: Segmentation fault\n"
				"       |\n"
#ifdef BUILD_ID
				"       | Cuberite " BUILD_SERIES_NAME " (id: " BUILD_ID ")\n"
				"       | from commit " BUILD_COMMIT_ID "\n"
#endif
			);

			std::signal(SIGSEGV, SIG_DFL);
			return;
		}
		case SIGABRT:
#ifdef SIGABRT_COMPAT
		case SIGABRT_COMPAT:
#endif
		{
			PrintStackTrace();

			LOGERROR(
				"Failure report: \n\n"
				"  :(   | Cuberite has encountered an error and needs to close\n"
				"       | SIGABRT: Server self-terminated due to an internal fault\n"
				"       |\n"
#ifdef BUILD_ID
				"       | Cuberite " BUILD_SERIES_NAME " (id: " BUILD_ID ")\n"
				"       | from commit " BUILD_COMMIT_ID "\n"
#endif
			);

			std::signal(SIGSEGV, SIG_DFL);
			return;
		}
		case SIGINT:
		case SIGTERM:
		{
			// Server is shutting down, wait for it...
			cRoot::Stop();
			return;
		}
	}
}

#ifdef __clang__
#pragma clang diagnostic pop
#endif





#ifdef _WIN32

/** Handle CTRL events in windows, including console window close. */
static BOOL CtrlHandler(DWORD fdwCtrlType)
{
	cRoot::Stop();
	LOGD("Terminate event raised from the Windows CtrlHandler");

	// Delay as much as possible to try to get the server to shut down cleanly - 10 seconds given by Windows:
	std::this_thread::sleep_for(std::chrono::seconds(10));

	// Returning from main() automatically aborts this handler thread.

	return TRUE;
}

#endif





namespace ConsoleSignalHandler
{
	static void Register()
	{
		std::signal(SIGSEGV, NonCtrlHandler);
		std::signal(SIGTERM, NonCtrlHandler);
		std::signal(SIGINT, NonCtrlHandler);
		std::signal(SIGABRT, NonCtrlHandler);
#ifdef SIGABRT_COMPAT
		std::signal(SIGABRT_COMPAT, NonCtrlHandler);
#endif
#ifdef SIGPIPE
		std::signal(SIGPIPE, SIG_IGN);  // Ignore (PR #2487).
#endif

#ifdef _WIN32
		SetConsoleCtrlHandler(reinterpret_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE);
#endif
	}
};