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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
|
/**
* @file llapp.h
* @brief Declaration of the LLApp class.
*
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLAPP_H
#define LL_LLAPP_H
#include <map>
#include "llcond.h"
#include "llrun.h"
#include "llsd.h"
#include <atomic>
#include <chrono>
// Forward declarations
class LLErrorThread;
class LLLiveFile;
#if LL_LINUX
#include <signal.h>
#endif
typedef void (*LLAppErrorHandler)();
#if !LL_WINDOWS
extern S32 LL_SMACKDOWN_SIGNAL;
extern S32 LL_HEARTBEAT_SIGNAL;
// Clear all of the signal handlers (which we want to do for the child process when we fork
void clear_signals();
#endif
namespace google_breakpad {
class ExceptionHandler; // See exception_handler.h
}
class LL_COMMON_API LLApp
{
friend class LLErrorThread;
public:
typedef enum e_app_status
{
APP_STATUS_RUNNING, // The application is currently running - the default status
APP_STATUS_QUITTING, // The application is currently quitting - threads should listen for this and clean up
APP_STATUS_STOPPED, // The application is no longer running - tells the error thread it can exit
APP_STATUS_ERROR // The application had a fatal error occur - tells the error thread to run
} EAppStatus;
LLApp();
virtual ~LLApp();
protected:
LLApp(LLErrorThread* error_thread);
void commonCtor();
public:
/**
* @brief Return the static app instance if one was created.
*/
static LLApp* instance();
/** @name Runtime options */
//@{
/**
* @brief Enumeration to specify option priorities in highest to
* lowest order.
*/
enum OptionPriority
{
PRIORITY_RUNTIME_OVERRIDE,
PRIORITY_COMMAND_LINE,
PRIORITY_SPECIFIC_CONFIGURATION,
PRIORITY_GENERAL_CONFIGURATION,
PRIORITY_DEFAULT,
PRIORITY_COUNT
};
/**
* @brief Get the application option at the highest priority.
*
* If the return value is undefined, the option does not exist.
* @param name The name of the option.
* @return Returns the option data.
*/
LLSD getOption(const std::string& name) const;
/**
* @brief Parse ASCII command line options and insert them into
* application command line options.
*
* The name inserted into the option will have leading option
* identifiers (a minus or double minus) stripped. All options
* with values will be stored as a string, while all options
* without values will be stored as true.
* @param argc The argc passed into main().
* @param argv The argv passed into main().
* @return Returns true if the parse succeeded.
*/
bool parseCommandOptions(int argc, char** argv);
/**
* @brief Parse Unicode command line options and insert them into
* application command line options.
*
* The name inserted into the option will have leading option
* identifiers (a minus or double minus) stripped. All options
* with values will be stored as a string, while all options
* without values will be stored as true.
* @param argc The argc passed into main().
* @param wargv The wargv passed into main().
* @return Returns true if the parse succeeded.
*/
bool parseCommandOptions(int argc, wchar_t** wargv);
/**
* @brief Keep track of live files automatically.
*
* *TODO: it currently uses the <code>addToEventTimer()</code> API
* instead of the runner. I should probalby use the runner.
*
* *NOTE: DO NOT add the livefile instance to any kind of check loop.
*
* @param livefile A valid instance of an LLLiveFile. This LLApp
* instance will delete the livefile instance.
*/
void manageLiveFile(LLLiveFile* livefile);
/**
* @brief Set the options at the specified priority.
*
* This function completely replaces the options at the priority
* level with the data specified. This function will make sure
* level and data might be valid before doing the replace.
* @param level The priority level of the data.
* @param data The data to set.
* @return Returns true if the option was set.
*/
bool setOptionData(OptionPriority level, LLSD data);
/**
* @brief Get the option data at the specified priority.
*
* This method is probably not so useful except when merging
* information.
* @param level The priority level of the data.
* @return Returns The data (if any) at the level priority.
*/
LLSD getOptionData(OptionPriority level);
//@}
//
// Main application logic
//
virtual bool init() = 0; // Override to do application initialization
//
// cleanup()
//
// It's currently assumed that the cleanup() method will only get
// called from the main thread or the error handling thread, as it will
// likely do thread shutdown, among other things.
//
virtual bool cleanup() = 0; // Override to do application cleanup
//
// frame()
//
// Pass control to the application for a single frame. Returns 'done'
// flag: if frame() returns false, it expects to be called again.
//
virtual bool frame() = 0; // Override for application body logic
//
// Crash logging
//
void disableCrashlogger(); // Let the OS handle the crashes
static bool isCrashloggerDisabled(); // Get the here above set value
//
// Application status
//
static void setQuitting(); // Set status to QUITTING, the app is now shutting down
static void setStopped(); // Set status to STOPPED, the app is done running and should exit
static void setError(); // Set status to ERROR, the error handler should run
static bool isStopped();
static bool isRunning();
static bool isQuitting();
static bool isError();
static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not)
static int getPid();
//
// Sleep for specified time while still running
//
// For use by a coroutine or thread that performs some maintenance on a
// periodic basis. (See also LLEventTimer.) This method supports the
// pattern of an "infinite" loop that sleeps for some time, performs some
// action, then sleeps again. The trouble with literally sleeping a worker
// thread is that it could potentially sleep right through attempted
// application shutdown. This method avoids that by returning false as
// soon as the application status changes away from APP_STATUS_RUNNING
// (isRunning()).
//
// sleep() returns true if it sleeps undisturbed for the entire specified
// duration. The idea is that you can code 'while sleep(duration) ...',
// which will break the loop once shutdown begins.
//
// Since any time-based LLUnit should be implicitly convertible to
// F32Milliseconds, accept that specific type as a proxy.
static bool sleep(F32Milliseconds duration);
// Allow any duration defined in terms of <chrono>.
// One can imagine a wonderfully general bidirectional conversion system
// between any type derived from LLUnits::LLUnit<T, LLUnits::Seconds> and
// any std::chrono::duration -- but that doesn't yet exist.
template <typename Rep, typename Period>
bool sleep(const std::chrono::duration<Rep, Period>& duration)
{
// wait_for_unequal() has the opposite bool return convention
return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING);
}
/** @name Error handling methods */
//@{
/**
* @brief Do our generic platform-specific error-handling setup --
* signals on unix, structured exceptions on windows.
*
* DO call this method if your app will either spawn children or be
* spawned by a launcher.
* Call just after app object construction.
* (Otherwise your app will crash when getting signals,
* and will not core dump.)
*
* DO NOT call this method if your application has specialized
* error handling code.
*/
void setupErrorHandling(bool mSecondInstance=false);
void setErrorHandler(LLAppErrorHandler handler);
static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
//@}
// the maximum length of the minidump filename returned by getMiniDumpFilename()
static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
// change the directory where Breakpad minidump files are written to
void setMiniDumpDir(const std::string &path);
void setDebugFileNames(const std::string &path);
// Return the Google Breakpad minidump filename after a crash.
char *getMiniDumpFilename() { return mMinidumpPath; }
std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; }
// Write out a Google Breakpad minidump file.
void writeMiniDump();
/**
* @brief Get a reference to the application runner
*
* Please use the runner with caution. Since the Runner usage
* pattern is not yet clear, this method just gives access to it
* to add and remove runnables.
* @return Returns the application runner. Do not save the
* pointer past the caller's stack frame.
*/
LLRunner& getRunner() { return mRunner; }
public:
typedef std::map<std::string, std::string> string_map;
string_map mOptionMap; // Contains all command-line options and arguments in a map
protected:
static void setStatus(EAppStatus status); // Use this to change the application status.
static LLScalarCond<EAppStatus> sStatus; // Reflects current application status
static BOOL sErrorThreadRunning; // Set while the error thread is running
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting.
std::string mDumpPath; //output path for google breakpad. Dependency workaround.
/**
* @brief This method is called once a frame to do once a frame tasks.
*/
void stepFrame();
private:
void startErrorThread();
// Contains the filename of the minidump file after a crash.
char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];
std::string mStaticDebugFileName;
std::string mDynamicDebugFileName;
// *NOTE: On Windows, we need a routine to reset the structured
// exception handler when some evil driver has taken it over for
// their own purposes
typedef int(*signal_handler_func)(int signum);
static LLAppErrorHandler sErrorHandler;
// Default application threads
LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback
// This is the application level runnable scheduler.
LLRunner mRunner;
/** @name Runtime option implementation */
//@{
// The application options.
LLSD mOptions;
// The live files for this application
std::vector<LLLiveFile*> mLiveFiles;
//@}
private:
// the static application instance if it was created.
static LLApp* sApplication;
google_breakpad::ExceptionHandler * mExceptionHandler;
#if !LL_WINDOWS
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
#endif
public:
static BOOL sLogInSignal;
};
#endif // LL_LLAPP_H
|