FlightGear next
bootstrap.cxx
Go to the documentation of this file.
1// bootstrap.cxx -- bootstrap routines: main()
2//
3// Written by Curtis Olson, started May 1997.
4//
5// Copyright (C) 1997 - 2002 Curtis L. Olson - http://www.flightgear.org/~curt
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20//
21// $Id$
22
23#include <config.h>
24
25#ifdef HAVE_WINDOWS_H
26#include <windows.h>
27#endif
28
29#if defined(__linux__)
30// set link for setting _GNU_SOURCE before including fenv.h
31// http://man7.org/linux/man-pages/man3/fenv.3.html
32
33 #ifndef _GNU_SOURCE
34 #define _GNU_SOURCE
35 #endif
36
37 #include <fenv.h>
38#endif
39
40#ifndef _WIN32
41# include <unistd.h> // for gethostname()
42#endif
43
44#include <iostream>
45#include <cerrno>
46#include <csignal>
47#include <cstdlib>
48#include <cstdio>
49#include <cstring>
50#include <clocale>
51
52#include <simgear/compiler.h>
53#include <simgear/structure/exception.hxx>
54#include <simgear/scene/tgdb/GroundLightManager.hxx>
55
56#include <osg/BufferObject>
57#include <osg/Texture>
58#include <osg/Version>
59#include <osgText/Font>
60
61#include "main.hxx"
62#include <GUI/MessageBox.hxx>
63#include <Main/fg_init.hxx>
64#include <Main/fg_props.hxx>
65#include <Main/globals.hxx>
66#include <Main/options.hxx>
69#include <Viewer/fgviewer.hxx>
70
71#include "fg_os.hxx"
72
73#if defined(HAVE_QT)
74#include <GUI/QtLauncher.hxx>
75#endif
76
77using std::cerr;
78using std::endl;
79
80std::string homedir;
81std::string hostname;
82
83// forward declaration.
84void fgExitCleanup();
85
86static void initFPE(bool enableExceptions);
87
88#if defined(__linux__)
89
90static void handleFPE(int);
91static void
92initFPE (bool fpeAbort)
93{
94 if (fpeAbort) {
95 int except = fegetexcept();
96 feenableexcept(except | FE_DIVBYZERO | FE_INVALID);
97 } else {
98 signal(SIGFPE, handleFPE);
99 }
100}
101
102static void handleFPE(int)
103{
104 feclearexcept(FE_ALL_EXCEPT);
105 SG_LOG(SG_GENERAL, SG_ALERT, "Floating point interrupt (SIGFPE)");
106 signal(SIGFPE, handleFPE);
107}
108#elif defined (SG_WINDOWS)
109
110static void initFPE(bool fpeAbort)
111{
112// Enable floating-point exceptions for Windows
113 if (fpeAbort) {
114 // set following link for what this does (note it does set SSE
115 // flags too, it's not just for the x87 FPU)
116 // http://msdn.microsoft.com/en-us/library/e9b52ceh.aspx
117 _control87( _EM_INEXACT, _MCW_EM );
118 }
119}
120
121#else
122static void initFPE(bool)
123{
124 // Ignore floating-point exceptions on FreeBSD, OS-X, other Unices
125 signal(SIGFPE, SIG_IGN);
126}
127#endif
128
129#if defined(SG_WINDOWS)
130int main ( int argc, char **argv );
131int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
132 LPSTR lpCmdLine, int nCmdShow)
133{
134 // convert wchar_t args to UTF-8 which is what we expect cross-platform
135 int numArgs = 0;
136 LPWSTR* wideArgs = CommandLineToArgvW(GetCommandLineW(), &numArgs);
137
138 std::vector<char*> utf8Args;
139 utf8Args.resize(numArgs);
140
141 for (int a = 0; a < numArgs; ++a) {
142 const auto s = simgear::strutils::convertWStringToUtf8(wideArgs[a]);
143 // note we leak these (strudp calls malloc) but not a big concern
144 utf8Args[a] = strdup(s.c_str());
145 }
146
147 main(numArgs, utf8Args.data());
148}
149
150// see https://stackoverflow.com/questions/35572792/setlocale-stuck-on-windows
151// for why we need this
152bool checkUniversalCRTVersion()
153{
154 DWORD dwSize = 0;
155 VS_FIXEDFILEINFO *pFileInfo = NULL;
156 UINT puLenFileInfo = 0;
157
158 // Get the version information for the file requested
159 dwSize = GetFileVersionInfoSizeA("ucrtbase.dll", NULL);
160 if (dwSize == 0) {
161 return false;
162 }
163
164 std::vector<BYTE> versionInfo;
165 versionInfo.resize(dwSize);
166
167 if (!GetFileVersionInfoA("ucrtbase.dll", 0, dwSize, versionInfo.data())) {
168 return false;
169 }
170
171 if (!VerQueryValue(versionInfo.data(), TEXT("\\"), (LPVOID*)&pFileInfo, &puLenFileInfo)) {
172 return false;
173 }
174
175 const WORD majorVersion = pFileInfo->dwFileVersionMS >> 16;
176 const WORD minorVersion = pFileInfo->dwFileVersionMS & 0xffff;
177 const WORD buildVersion = pFileInfo->dwFileVersionLS >> 16;
178 const WORD releaseVersion = pFileInfo->dwFileVersionLS & 0xffff;
179
180 // char buffer[256];
181 // snprintf(buffer, 256, "File Version: %d.%d.%d.%d\n",
182 // majorVersion, minorVersion, buildVersion, releaseVersion);
183 // OutputDebugString(buffer);
184 return (buildVersion > 10586);
185}
186
187#endif
188
189#if defined(__GNUC__)
190#include <execinfo.h>
191#include <cxxabi.h>
192void segfault_handler(int signo) {
193
194 fprintf(stderr, "Error: caught signal %d:\n", signo);
195
196 #ifndef __OpenBSD__
197 void *array[128];
198 size_t size;
199 size = backtrace(array, 128);
200 if (size) {
201 char** list = backtrace_symbols(array, size);
202 size_t fnlen = 256;
203 char* fname = (char*)malloc(fnlen);
204
205 for (size_t i=1; i<size; i++) {
206 char *begin = 0, *offset = 0, *end = 0;
207 for (char *p = list[i]; *p; ++p) {
208 if (*p == '(') begin = p;
209 else if (*p == '+') offset = p;
210 else if (*p == ')' && offset) {
211 end = p;
212 break;
213 }
214 }
215
216 if (begin && offset && end && begin<offset) {
217 *begin++ = '\0'; *offset++ = '\0'; *end = '\0';
218
219 int status;
220 char* ret = abi::__cxa_demangle(begin, fname, &fnlen, &status);
221 if (status == 0) {
222 fname = ret;
223 fprintf(stderr, " %s : %s+%s\n", list[i], fname, offset);
224 }
225 else
226 fprintf(stderr, " %s : %s()+%s\n", list[i], begin, offset);
227 }
228 else
229 fprintf(stderr, " %s\n", list[i]);
230 }
231
232 free(fname);
233 free(list);
234 }
235 #endif
236
237 std::abort();
238}
239#endif
240
241[[noreturn]] static void fg_terminate()
242{
243 cerr << "Running FlightGear's terminate handler. The program is going to "
244 "exit due to a fatal error condition, sorry." << std::endl;
245 std::abort();
246}
247
248// Detect SSE2 support for x86, it is always available for x86_64
249#if defined(__i386__)
250# if defined(SG_WINDOWS)
251# include <intrin.h>
252# define get_cpuid(a,b) __cpuid(a,b)
253# else
254# include <cpuid.h>
255# define get_cpuid(a,b) __cpuid(b,a[0],a[1],a[2],a[3])
256# endif
257# define CPUID_GETFEATURES 1
258# define CPUID_FEAT_EDX_SSE2 (1 << 26)
259bool detectSIMD()
260{
261 static int regs[4] = {0,0,0,0};
262 get_cpuid(regs, CPUID_GETFEATURES);
263 return (regs[3] & CPUID_FEAT_EDX_SSE2);
264}
265#else
266bool detectSIMD() { return true; }
267#endif
268
270
271// Main entry point; catch any exceptions that have made it this far.
272int main ( int argc, char **argv )
273{
274 // we don't want to accidently show a GUI box and block startup in
275 // non_GUI setups, so check this value early here, before options are
276 // processed
277 const bool headless = flightgear::Options::checkForArgDisable(argc, argv, "gui");
279
280#ifdef ENABLE_SIMD
281 if (!detectSIMD()) {
283 "Fatal error",
284 "SSE2 support not detected, but this version of FlightGear requires "
285 "SSE2 hardware support.");
286 }
287#endif
288
289#if defined(SG_WINDOWS)
290 // Don't show blocking "no disk in drive" error messages on Windows 7,
291 // silently return errors to application instead.
292 // See Microsoft MSDN #ms680621: "GUI apps should specify SEM_NOOPENFILEERRORBOX"
293 SetErrorMode(SEM_NOOPENFILEERRORBOX);
294
295 hostname = ::getenv( "COMPUTERNAME" );
296
297 if (!checkUniversalCRTVersion()) {
299 "Fatal error",
300 "The Microsoft Universal CRT on this computer is too old to run FlightGear. "
301 "Please use Windows Update to install a more recent Universal CRT version.");
302 }
303#else
304 // Unix(alike) systems
305 char _hostname[256];
306 gethostname(_hostname, 256);
307 hostname = _hostname;
308 signal(SIGPIPE, SIG_IGN);
309#endif
310
312
313#if defined(HAVE_SENTRY)
314 const bool noSentry = flightgear::Options::checkForArgDisable(argc, argv, "sentry");
315 if (!noSentry) {
317 }
318 #endif
319
320// if we're not using the normal crash-reported, install our
321// custom segfault handler on Linux, in debug builds.
322// NB On OpenBSD this seems to lose info about where the signal
323// happened, so is disabled.
324#if !defined(SG_WINDOWS) && !defined(NDEBUG) && !defined(__OpenBSD__)
326 signal(SIGSEGV, segfault_handler);
327 }
328#endif
329
331
332 // pick up all user locale settings, but force C locale for numerical/sorting
333 // conversions because we have lots of code which assumes standard
334 // formatting
335 setlocale(LC_ALL, "");
336 setlocale(LC_NUMERIC, "C");
337 setlocale(LC_COLLATE, "C");
338
339 if (flightgear::Options::checkForArg(argc, argv, "uninstall")) {
340 return fgUninstall();
341 }
342
343 bool fgviewer = flightgear::Options::checkForArg(argc, argv, "fgviewer");
344 int exitStatus = EXIT_FAILURE;
345 try {
346 // http://code.google.com/p/flightgear-bugs/issues/detail?id=1231
347 // ensure sglog is inited before atexit() is registered, so logging
348 // is possible inside fgExitCleanup
349 sglog();
350
351 std::set_terminate(fg_terminate);
352 atexit(fgExitCleanup);
353
354 if (fgviewer) {
355 exitStatus = fgviewerMain(argc, argv);
356 } else {
357 exitStatus = fgMainInit(argc, argv);
358 }
359
360 } catch (const sg_throwable &t) {
361 std::string info;
362 if (std::strlen(t.getOrigin()) != 0)
363 info = std::string("received from ") + t.getOrigin();
365 "Fatal exception", t.getFormattedMessage(), info);
366 } catch (const std::bad_alloc&) {
368 "FlightGear ran out of memory and must exit.", "Consider adjusting your settings or closing other applications.");
369 } catch (const std::exception &e ) {
370 flightgear::fatalMessageBoxWithoutExit("Fatal exception", e.what());
371 } catch (const std::string &s) {
372 flightgear::fatalMessageBoxWithoutExit("Fatal exception", s);
373 } catch (const flightgear::FatalErrorException&) {
374 // we already showed the message box, just carry on to exit
375 } catch (const char *s) {
376 std::cerr << "Fatal error (const char*): " << s << std::endl;
377 } catch (...) {
378 flightgear::sentryReportException("Unknown main loop exception");
379 std::cerr << "Unknown exception in the main loop. Aborting..." << std::endl;
380 if (errno)
381 perror("Possible cause");
382 }
383
384#if defined(HAVE_QT)
386#endif
387 return exitStatus;
388}
389
390// do some clean up on exit. Specifically we want to delete the sound-manager,
391// so OpenAL device and context are released cleanly
393{
394 flightgear::addSentryBreadcrumb("starting fgExitCleanup", "info");
395
396 if (_bootstrap_OSInit != 0) {
398 }
399
401
402 // you might imagine we'd call shutdownQtApp here, but it's not safe to do
403 // so in an atexit handler, and crashes on Mac. Thiago states this explicitly:
404 // https://bugreports.qt.io/browse/QTBUG-48709
405
406 // on the common exit path globals is already deleted, and NULL,
407 // so this only happens on error paths.
408 delete globals;
409
410 flightgear::addSentryBreadcrumb("finished deleting globals", "info");
411
412 simgear::shutdownLogging();
414}
415
416void fgExit(int status)
417{
418#if defined(HAVE_QT)
420#endif
421 exit(status);
422}
423
#define p(x)
#define i(x)
bool detectSIMD()
void fgExitCleanup()
void fgExit(int status)
int _bootstrap_OSInit
static void initFPE(bool enableExceptions)
static void fg_terminate()
static bool checkForArgEnable(int argc, char *argv[], const std::string &checkArg)
Return true when user explicitly enabled boolean option, otherwise false.
Definition options.cxx:3681
static bool checkForArg(int argc, char *argv[], const char *arg)
Check if the arguments array contains a particular string (with a '–' or '-' prefix).
Definition options.cxx:3603
static bool checkForArgDisable(int argc, char *argv[], const std::string &checkArg)
Return true when user explicitly disabled boolean option by set false value.
Definition options.cxx:3687
int main()
int fgUninstall()
Definition fg_init.cxx:1513
void fgOSCloseWindow()
static int status
char * homedir
Definition fgjs.cxx:224
char * hostname
Definition fgjs.cxx:225
int fgviewerMain(int argc, char **argv)
Definition fgviewer.cxx:107
FGGlobals * globals
Definition globals.cxx:142
int fgMainInit(int argc, char **argv)
Definition main.cxx:537
MessageBoxResult fatalMessageBoxWithoutExit(const std::string &caption, const std::string &msg, const std::string &moreText, bool reportToSentry)
void addSentryBreadcrumb(const std::string &, const std::string &)
void sentryReportException(const std::string &, const std::string &)
void fatalMessageBoxThenExit(const std::string &caption, const std::string &msg, const std::string &moreText, int exitStatus, bool reportToSentry)
void setHeadlessMode(bool headless)
void shutdownQtApp()