phoenix-firestorm/indra/llcommon/llapp.h

351 lines
12 KiB
C++

/**
* @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 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
class LL_COMMON_API LLApp
{
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();
/**
* @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();
static void notifyOutOfDiskSpace();
//
// 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
//@}
// 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 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; }
#ifdef LL_WINDOWS
virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { }
#endif
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 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();
virtual void sendOutOfDiskSpaceNotification();
private:
// 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;
// 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;
#if !LL_WINDOWS
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
#endif
private:
#ifdef LL_RELEASE_FOR_DOWNLOAD
static constexpr bool sLogInSignal = false;
#else
static constexpr bool sLogInSignal = true;
#endif
};
#endif // LL_LLAPP_H