Fixes: NB#212024 - Application launcher should be usable (improve performance) also at boot

RevBy: Antti Kervinen

Details:
--boot-mode starts applauncherd in the boot mode:
* Boosters won't initialize cache
* Booster respawn delay is zero

Sending SIGUSR1 forces the launcher to enter the normal mode again.
pull/1/head
Jussi Lind 15 years ago
parent 5af417187a
commit 0ff715fb64

@ -3,7 +3,9 @@ project(Applauncherd)
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
cmake_policy(VERSION 2.6) cmake_policy(VERSION 2.6)
set(CMAKE_VERBOSE_MAKEFILE ON) #
# NOTE: For verbose build use VERBOSE=1
#
# Default C++-flags. Sub-builds might alter these. # Default C++-flags. Sub-builds might alter these.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -g -O3 -Wl,--as-needed") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -g -O3 -Wl,--as-needed")
@ -78,6 +80,8 @@ add_definitions(-DBOOSTER_PLUGIN_DIR="/usr/lib/applauncherd")
add_definitions(-DSINGLE_INSTANCE_PATH="/usr/bin/single-instance") add_definitions(-DSINGLE_INSTANCE_PATH="/usr/bin/single-instance")
# Disable debug logging, only error and warning messages get logged # Disable debug logging, only error and warning messages get logged
# Currently effective only for invoker. Launcher part recognizes --debug
# which enables console echoing and debug messages.
add_definitions(-DDEBUG_LOGGING_DISABLED) add_definitions(-DDEBUG_LOGGING_DISABLED)
# Build with test coverage switch if BUILD_COVERAGE environment variable is set # Build with test coverage switch if BUILD_COVERAGE environment variable is set

@ -49,7 +49,7 @@
// Delay before exit // Delay before exit
static const unsigned int DEFAULT_DELAY = 0; static const unsigned int DEFAULT_DELAY = 0;
static const unsigned int RESPAWN_DELAY = 2; static const unsigned int RESPAWN_DELAY = 3;
static const unsigned int MAX_RESPAWN_DELAY = 10; static const unsigned int MAX_RESPAWN_DELAY = 10;
static const unsigned char EXIT_STATUS_APPLICATION_CONNECTION_LOST = 0xfa; static const unsigned char EXIT_STATUS_APPLICATION_CONNECTION_LOST = 0xfa;

@ -52,7 +52,8 @@ Booster::Booster() :
m_connection(NULL), m_connection(NULL),
m_oldPriority(0), m_oldPriority(0),
m_oldPriorityOk(false), m_oldPriorityOk(false),
m_spaceAvailable(0) m_spaceAvailable(0),
m_bootMode(false)
{} {}
Booster::~Booster() Booster::~Booster()
@ -64,21 +65,20 @@ Booster::~Booster()
m_appData = NULL; m_appData = NULL;
} }
bool Booster::preload()
{
return true;
}
void Booster::initialize(int initialArgc, char ** initialArgv, int newPipeFd[2], void Booster::initialize(int initialArgc, char ** initialArgv, int newPipeFd[2],
int socketFd, SingleInstance * singleInstance) int socketFd, SingleInstance * singleInstance,
bool newBootMode)
{ {
m_bootMode = newBootMode;
setPipeFd(newPipeFd); setPipeFd(newPipeFd);
// Drop priority (nice = 10) // Drop priority (nice = 10)
pushPriority(10); pushPriority(10);
// Preload stuff // Preload stuff
preload(); if (!m_bootMode)
preload();
// Rename process to temporary booster process name, e.g. "booster-m" // Rename process to temporary booster process name, e.g. "booster-m"
const char * tempArgv[] = {boosterTemporaryProcessName().c_str()}; const char * tempArgv[] = {boosterTemporaryProcessName().c_str()};
@ -139,6 +139,11 @@ void Booster::initialize(int initialArgc, char ** initialArgv, int newPipeFd[2],
prctl(PR_SET_DUMPABLE, 1); prctl(PR_SET_DUMPABLE, 1);
} }
bool Booster::bootMode() const
{
return m_bootMode;
}
void Booster::sendDataToParent() void Booster::sendDataToParent()
{ {
// Signal the parent process that it can create a new // Signal the parent process that it can create a new

@ -68,15 +68,16 @@ public:
/*! /*!
* \brief Initializes the booster process. * \brief Initializes the booster process.
* \param initialArgc argc of the parent process.
* \param initialArgv argv of the parent process.
* \param pipefd pipe used to communicate with the parent process.
* \param socketFd File socket used to get commands from the invoker.
* \param singleInstance Pointer to a valid SingleInstance object.
* \param bootMode Booster-specific preloads are not executed if true.
*/ */
virtual void initialize(int initialArgc, char ** initialArgv, int pipefd[2], virtual void initialize(int initialArgc, char ** initialArgv, int pipefd[2],
int socketFd, SingleInstance * singleInstance); int socketFd, SingleInstance * singleInstance,
bool bootMode);
/*!
* \brief Preload libraries.
* Override in the custom Booster.
*/
virtual bool preload();
/*! /*!
* \brief Run the application to be invoked. * \brief Run the application to be invoked.
@ -141,17 +142,21 @@ public:
* \brief Return the communication socket used by a Booster. * \brief Return the communication socket used by a Booster.
* This method returns the socket used between invoker and the Booster. * This method returns the socket used between invoker and the Booster.
* (common to all Boosters of the type). Override in the custom Booster. * (common to all Boosters of the type). Override in the custom Booster.
* \return Path to the socket file * \return Path to the socket file.
*/ */
virtual const string & socketId() const = 0; virtual const string & socketId() const = 0;
protected: //! Return true, if in boot mode.
bool bootMode() const;
//! Set nice value and store the old priority. Return true on success. protected:
bool pushPriority(int nice);
//! Restore the old priority stored by the previous successful setPriority(). /*!
bool popPriority(); * \brief Preload libraries / initialize cache etc.
* Called from initialize if not in the boot mode.
* Re-implement in the custom Booster.
*/
virtual bool preload() = 0;
/*! /*!
* \brief Wait for connection from invoker and read the input. * \brief Wait for connection from invoker and read the input.
@ -163,6 +168,12 @@ protected:
*/ */
virtual bool receiveDataFromInvoker(int socketFd); virtual bool receiveDataFromInvoker(int socketFd);
//! Set nice value and store the old priority. Return true on success.
bool pushPriority(int nice);
//! Restore the old priority stored by the previous successful setPriority().
bool popPriority();
//! Sets pipe fd's used to communicate with the parent process //! Sets pipe fd's used to communicate with the parent process
void setPipeFd(int pipeFd[2]); void setPipeFd(int pipeFd[2]);
@ -209,6 +220,9 @@ private:
//! Original space available for arguments //! Original space available for arguments
int m_spaceAvailable; int m_spaceAvailable;
//! True, if being run in boot mode.
bool m_bootMode;
#ifdef HAVE_CREDS #ifdef HAVE_CREDS
//! filter out invoker-specific credentials from boosted application //! filter out invoker-specific credentials from boosted application
static void filterOutCreds(creds_t creds); static void filterOutCreds(creds_t creds);

@ -33,7 +33,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <signal.h>
#include <fcntl.h> #include <fcntl.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <glob.h> #include <glob.h>
@ -46,6 +45,7 @@ const int Daemon::m_boosterSleepTime = 2;
Daemon::Daemon(int & argc, char * argv[]) : Daemon::Daemon(int & argc, char * argv[]) :
m_daemon(false), m_daemon(false),
m_quiet(false), m_quiet(false),
m_bootMode(false),
m_socketManager(new SocketManager), m_socketManager(new SocketManager),
m_singleInstance(new SingleInstance) m_singleInstance(new SingleInstance)
{ {
@ -69,9 +69,24 @@ Daemon::Daemon(int & argc, char * argv[]) :
m_initialArgv = argv; m_initialArgv = argv;
m_initialArgc = argc; m_initialArgc = argc;
if (pipe(m_pipefd) == -1) if (pipe(m_boosterPipeFd) == -1)
{ {
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: Creating a pipe failed!\n"); Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: Creating a pipe for boosters failed!\n");
}
if (pipe(m_sigChldPipeFd) == -1)
{
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: Creating a pipe for SIGCHLD failed!\n");
}
if (pipe(m_sigTermPipeFd) == -1)
{
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: Creating a pipe for SIGTERM failed!\n");
}
if (pipe(m_sigUsr1PipeFd) == -1)
{
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: Creating a pipe for SIGUSR1 failed!\n");
} }
// Daemonize if desired // Daemonize if desired
@ -181,71 +196,134 @@ void Daemon::run()
// Main loop // Main loop
while (true) while (true)
{ {
// Wait for something appearing in the pipe. There should first // Variables used by the select call
// appear a character representing the type of a booster and then fd_set rfds;
// pid of the invoker process that communicated with that booster. int ndfs = 0;
char msg;
ssize_t count = read(m_pipefd[0], static_cast<void *>(&msg), 1); // Init data for select
if (count) FD_ZERO(&rfds);
FD_SET(m_boosterPipeFd[0], &rfds);
ndfs = std::max(ndfs, m_boosterPipeFd[0]);
FD_SET(m_sigChldPipeFd[0], &rfds);
ndfs = std::max(ndfs, m_sigChldPipeFd[0]);
FD_SET(m_sigTermPipeFd[0], &rfds);
ndfs = std::max(ndfs, m_sigTermPipeFd[0]);
FD_SET(m_sigUsr1PipeFd[0], &rfds);
ndfs = std::max(ndfs, m_sigUsr1PipeFd[0]);
char buffer;
// Wait for something appearing in the pipes.
if (select(ndfs + 1, &rfds, NULL, NULL, NULL) > 0)
{ {
// Read pid of peer invoker Logger::logDebug("select done.");
pid_t invokerPid;
count = read(m_pipefd[0], static_cast<void *>(&invokerPid), sizeof(pid_t));
if (count < static_cast<ssize_t>(sizeof(pid_t))) // Check if a booster died
if (FD_ISSET(m_boosterPipeFd[0], &rfds))
{ {
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: pipe connection with booster failed"); Logger::logDebug("FD_ISSET(m_boosterPipeFd[0])");
readFromBoosterPipe(m_boosterPipeFd[0]);
} }
else
// Check if we got SIGCHLD
if (FD_ISSET(m_sigChldPipeFd[0], &rfds))
{ {
Logger::logDebug("Daemon: invoker's pid: %d \n", invokerPid); Logger::logDebug("FD_ISSET(m_sigChldPipeFd[0])");
read(m_sigChldPipeFd[0], &buffer, 1);
reapZombies();
} }
if (invokerPid != 0) // Check if we got SIGTERM
if (FD_ISSET(m_sigTermPipeFd[0], &rfds))
{ {
// Store booster - invoker pid pair Logger::logDebug("FD_ISSET(m_sigTermPipeFd[0])");
pid_t boosterPid = boosterPidForType(msg); read(m_sigTermPipeFd[0], &buffer, 1);
if (boosterPid) exit(EXIT_SUCCESS);
{
m_boosterPidToInvokerPid[boosterPid] = invokerPid;
}
} }
// Read booster respawn delay // Check if we got SIGUSR1
int delay; if (FD_ISSET(m_sigUsr1PipeFd[0], &rfds))
count = read(m_pipefd[0], static_cast<void *>(&delay), sizeof(int));
if (count < static_cast<ssize_t>(sizeof(int)))
{ {
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: pipe connection with booster failed"); Logger::logDebug("FD_ISSET(m_sigUsr1PipeFd[0])");
read(m_sigUsr1PipeFd[0], &buffer, 1);
enterNormalMode();
} }
else }
}
}
void Daemon::readFromBoosterPipe(int fd)
{
// There should first appear a character representing the type of a
// booster and then pid of the invoker process that communicated with
// that booster.
char msg;
ssize_t count = read(fd, static_cast<void *>(&msg), 1);
if (count)
{
// Read pid of peer invoker
pid_t invokerPid;
count = read(fd, static_cast<void *>(&invokerPid), sizeof(pid_t));
if (count < static_cast<ssize_t>(sizeof(pid_t)))
{
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: pipe connection with booster failed");
}
else
{
Logger::logDebug("Daemon: invoker's pid: %d \n", invokerPid);
}
if (invokerPid != 0)
{
// Store booster - invoker pid pair
pid_t boosterPid = boosterPidForType(msg);
if (boosterPid)
{ {
Logger::logDebug("Daemon: respawn delay: %d \n", delay); m_boosterPidToInvokerPid[boosterPid] = invokerPid;
} }
}
// Fork a new booster of the given type // Read booster respawn delay
int delay;
// 2nd param guarantees some time for the just launched application count = read(fd, static_cast<void *>(&delay), sizeof(int));
// to start up before forking new booster. Not doing this would
// slow down the start-up significantly on single core CPUs.
forkBooster(msg, delay); if (count < static_cast<ssize_t>(sizeof(int)))
{
Logger::logErrorAndDie(EXIT_FAILURE, "Daemon: pipe connection with booster failed");
} }
else else
{ {
Logger::logWarning("Daemon: Nothing read from the pipe\n"); Logger::logDebug("Daemon: respawn delay received: %d \n", delay);
} }
// Fork a new booster of the given type
// 2nd param guarantees some time for the just launched application
// to start up before forking new booster. Not doing this would
// slow down the start-up significantly on single core CPUs.
forkBooster(msg, delay);
}
else
{
Logger::logWarning("Daemon: Nothing read from the pipe\n");
} }
} }
void Daemon::killProcess(pid_t pid) const void Daemon::killProcess(pid_t pid, int signal) const
{ {
if (pid) if (pid)
{ {
if (kill(pid, SIGKILL) != 0) Logger::logDebug("Daemon: Killing pid %d with %d", pid, signal);
if (kill(pid, signal) != 0)
{ {
Logger::logError("Daemon: Failed to kill %d: %s\n", pid, strerror(errno)); Logger::logError("Daemon: Failed to kill %d: %s\n",
pid, strerror(errno));
} }
} }
} }
@ -273,8 +351,8 @@ void Daemon::loadSingleInstancePlugin()
void Daemon::loadBoosterPlugins() void Daemon::loadBoosterPlugins()
{ {
const char* PATTERN = "lib*booster.so"; const char* PATTERN = "lib*booster.so";
const int BUF_LEN = 256; const unsigned int BUF_LEN = 256;
if (strlen(PATTERN) + strlen(BOOSTER_PLUGIN_DIR) + 2 > BUF_LEN) if (strlen(PATTERN) + strlen(BOOSTER_PLUGIN_DIR) + 2 > BUF_LEN)
{ {
@ -322,6 +400,9 @@ void Daemon::loadBoosterPlugins()
void Daemon::forkBooster(char type, int sleepTime) void Daemon::forkBooster(char type, int sleepTime)
{ {
// Invalidate current booster pid for the given type
setPidToBooster(type, 0);
// Fork a new process // Fork a new process
pid_t newPid = fork(); pid_t newPid = fork();
@ -333,12 +414,25 @@ void Daemon::forkBooster(char type, int sleepTime)
// Reset used signal handlers // Reset used signal handlers
signal(SIGCHLD, SIG_DFL); signal(SIGCHLD, SIG_DFL);
signal(SIGTERM, SIG_DFL); signal(SIGTERM, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
// Will get this signal if applauncherd dies // Will get this signal if applauncherd dies
prctl(PR_SET_PDEATHSIG, SIGHUP); prctl(PR_SET_PDEATHSIG, SIGHUP);
// Close unused read end // Close unused read end of the booster pipe
close(m_pipefd[0]); close(m_boosterPipeFd[0]);
// Close SIGCHLD pipe
close(m_sigChldPipeFd[0]);
close(m_sigChldPipeFd[1]);
// Close SIGTERM pipe
close(m_sigTermPipeFd[0]);
close(m_sigTermPipeFd[1]);
// Close SIGUSR1 pipe
close(m_sigUsr1PipeFd[0]);
close(m_sigUsr1PipeFd[1]);
// Close unused sockets inherited from daemon // Close unused sockets inherited from daemon
closeUnusedSockets(type); closeUnusedSockets(type);
@ -352,7 +446,8 @@ void Daemon::forkBooster(char type, int sleepTime)
// Guarantee some time for the just launched application to // Guarantee some time for the just launched application to
// start up before forking new booster if needed. // start up before forking new booster if needed.
if (sleepTime) // Not done if in the boot mode.
if (!m_bootMode && sleepTime)
sleep(sleepTime); sleep(sleepTime);
Logger::logDebug("Daemon: Running a new Booster of type '%c'", type); Logger::logDebug("Daemon: Running a new Booster of type '%c'", type);
@ -362,9 +457,9 @@ void Daemon::forkBooster(char type, int sleepTime)
if (booster) if (booster)
{ {
// Initialize and wait for commands from invoker // Initialize and wait for commands from invoker
booster->initialize(m_initialArgc, m_initialArgv, m_pipefd, booster->initialize(m_initialArgc, m_initialArgv, m_boosterPipeFd,
m_socketManager->findSocket(booster->socketId().c_str()), m_socketManager->findSocket(booster->socketId().c_str()),
m_singleInstance); m_singleInstance, m_bootMode);
// Run the current Booster // Run the current Booster
booster->run(m_socketManager); booster->run(m_socketManager);
@ -543,9 +638,9 @@ void Daemon::daemonize()
// Redirect standard file descriptors to /dev/null // Redirect standard file descriptors to /dev/null
// Close new file descriptors // Close new file descriptors
const int new_stdin = open("/dev/null", O_RDONLY); const int new_stdin = open("/dev/null", O_RDONLY);
if (new_stdin != -1) { if (new_stdin != -1) {
dup2(new_stdin, STDIN_FILENO); dup2(new_stdin, STDIN_FILENO);
close(new_stdin); close(new_stdin);
} }
@ -566,17 +661,67 @@ void Daemon::parseArgs(const ArgVect & args)
{ {
for (ArgVect::const_iterator i(args.begin()); i != args.end(); i++) for (ArgVect::const_iterator i(args.begin()); i != args.end(); i++)
{ {
if ((*i) == "--daemon") if ((*i) == "--daemon" || (*i) == "-d")
{ {
m_daemon = true; m_daemon = true;
} }
else if ((*i) == "--quiet") else if ((*i) == "--debug")
{
Logger::setDebugMode(true);
}
else if ((*i) == "--quiet" || (*i) == "-q")
{ {
m_quiet = true; m_quiet = true;
} }
else if ((*i) == "--boot-mode" || (*i) == "-b")
{
Logger::logInfo("Daemon: Boot mode set.");
m_bootMode = true;
}
} }
} }
int Daemon::sigChldPipeFd() const
{
return m_sigChldPipeFd[1];
}
int Daemon::sigTermPipeFd() const
{
return m_sigTermPipeFd[1];
}
int Daemon::sigUsr1PipeFd() const
{
return m_sigUsr1PipeFd[1];
}
void Daemon::enterNormalMode()
{
if (m_bootMode)
{
m_bootMode = false;
// Kill current boosters
killBoosters();
Logger::logInfo("Daemon: Exited boot mode.");
}
}
void Daemon::killBoosters()
{
TypeMap::iterator iter(m_boosterTypeToPid.begin());
while (iter != m_boosterTypeToPid.end())
{
killProcess(iter->second, SIGTERM);
iter++;
}
// NOTE!!: m_boosterTypeToPid must not be cleared
// in order to automatically start new boosters.
}
Daemon::~Daemon() Daemon::~Daemon()
{ {
delete m_socketManager; delete m_socketManager;

@ -37,6 +37,8 @@ using std::vector;
using std::map; using std::map;
#include <signal.h>
class Booster; class Booster;
class SocketManager; class SocketManager;
class SingleInstance; class SingleInstance;
@ -88,6 +90,15 @@ public:
//! Unlock file (lock is not needed in boosters) //! Unlock file (lock is not needed in boosters)
static void unlock(); static void unlock();
//! Get fd to write when SIGCHLD arrives
int sigChldPipeFd() const;
//! Get fd to write when SIGTERM arrives
int sigTermPipeFd() const;
//! Get fd to write when SIGUSR1 arrives
int sigUsr1PipeFd() const;
private: private:
//! Disable copy-constructor //! Disable copy-constructor
@ -118,8 +129,8 @@ private:
//! Don't use console for output //! Don't use console for output
void consoleQuiet(); void consoleQuiet();
//! Kill given pid with SIGKILL //! Kill given pid with SIGKILL by default
void killProcess(pid_t pid) const; void killProcess(pid_t pid, int signal = SIGKILL) const;
//! Load (dlopen()) booster plugins //! Load (dlopen()) booster plugins
void loadBoosterPlugins(); void loadBoosterPlugins();
@ -139,12 +150,29 @@ private:
//! Close all sockets NOT used by the given booster type. //! Close all sockets NOT used by the given booster type.
void closeUnusedSockets(char type); void closeUnusedSockets(char type);
//! Daemonize flag //! Read and process data from a booster pipe
void readFromBoosterPipe(int fd);
//! Enter normal mode (restart boosters with cache enabled)
void enterNormalMode();
//! Kill all active boosters with -9
void killBoosters();
//! Daemonize flag (--fork). Daemon forks if true.
bool m_daemon; bool m_daemon;
//! Debug print flag //! Debug print flag (--quiet). Daemon closes fd's 0 - 2 if true.
bool m_quiet; bool m_quiet;
/*! Flag indicating boot mode (--boot-mode). If true, then:
* - Caches won't be initialized.
* - Booster respwan delay is 0.
*
* Normal mode is activated by firing SIGUSR1.
*/
bool m_bootMode;
//! Vector of current child PID's //! Vector of current child PID's
typedef vector<pid_t> PidVect; typedef vector<pid_t> PidVect;
PidVect m_children; PidVect m_children;
@ -157,8 +185,18 @@ private:
typedef map<char, pid_t> TypeMap; typedef map<char, pid_t> TypeMap;
TypeMap m_boosterTypeToPid; TypeMap m_boosterTypeToPid;
//! Pipe used to tell the parent that a new booster is needed //! Pipe used to tell the parent that a new booster is needed +
int m_pipefd[2]; //! some parameters.
int m_boosterPipeFd[2];
//! Pipe used to safely catch SIGCHLD
int m_sigChldPipeFd[2];
//! Pipe used to safely catch SIGTERM
int m_sigTermPipeFd[2];
//! Pipe used to safely catch SIGUSR1
int m_sigUsr1PipeFd[2];
//! Argument vector initially given to the launcher process //! Argument vector initially given to the launcher process
int m_initialArgc; int m_initialArgc;

@ -26,7 +26,7 @@
bool Logger::m_isOpened = false; bool Logger::m_isOpened = false;
bool Logger::m_echoMode = false; bool Logger::m_debugMode = false;
void Logger::openLog(const char * progName) void Logger::openLog(const char * progName)
{ {
@ -48,8 +48,8 @@ void Logger::writeLog(const int priority, const char * format, va_list ap)
{ {
if (Logger::m_isOpened) if (Logger::m_isOpened)
{ {
// In echo mode everything is printed also to stdout // In debug mode everything is printed also to stdout
if (m_echoMode) if (m_debugMode)
{ {
vprintf(format, ap); vprintf(format, ap);
printf("\n"); printf("\n");
@ -62,14 +62,13 @@ void Logger::writeLog(const int priority, const char * format, va_list ap)
void Logger::logDebug(const char * format, ...) void Logger::logDebug(const char * format, ...)
{ {
#ifndef DEBUG_LOGGING_DISABLED if (m_debugMode)
va_list(ap); {
va_start(ap, format); va_list(ap);
writeLog(LOG_DEBUG, format, ap); va_start(ap, format);
va_end(ap); writeLog(LOG_DEBUG, format, ap);
#else va_end(ap);
(void)format; }
#endif
} }
void Logger::logInfo(const char * format, ...) void Logger::logInfo(const char * format, ...)
@ -107,8 +106,8 @@ void Logger::logErrorAndDie(int code, const char * format, ...)
_exit(code); _exit(code);
} }
void Logger::setEchoMode(bool enable) void Logger::setDebugMode(bool enable)
{ {
Logger::m_echoMode = enable; Logger::m_debugMode = enable;
} }

@ -42,9 +42,9 @@ public:
*/ */
static void closeLog(); static void closeLog();
/*! /*!
* \brief Log a notice to the system message logger * \brief Log a debug to the system message logger.
* Effective only if Logger::setDebugMode(true) called;
* \param format String identical to a printf format string * \param format String identical to a printf format string
* \param additionalArgs Depending on the format string, the function may expect a * \param additionalArgs Depending on the format string, the function may expect a
* sequence of additional arguments, each containing one value to be inserted * sequence of additional arguments, each containing one value to be inserted
@ -52,7 +52,6 @@ public:
*/ */
static void logDebug(const char * format, ...); static void logDebug(const char * format, ...);
/*! /*!
* \brief Log an error to the system message logger * \brief Log an error to the system message logger
* \param format String identical to a printf format string * \param format String identical to a printf format string
@ -62,7 +61,6 @@ public:
*/ */
static void logError(const char * format, ...); static void logError(const char * format, ...);
/*! /*!
* \brief Log a warning to the system message logger * \brief Log a warning to the system message logger
* \param format String identical to a printf format string * \param format String identical to a printf format string
@ -72,7 +70,6 @@ public:
*/ */
static void logWarning(const char * format, ...); static void logWarning(const char * format, ...);
/*! /*!
* \brief Log a piece of information to the system message logger * \brief Log a piece of information to the system message logger
* \param format String identical to a printf format string * \param format String identical to a printf format string
@ -91,19 +88,20 @@ public:
*/ */
static void logErrorAndDie(int code, const char * format, ...); static void logErrorAndDie(int code, const char * format, ...);
/*! /*!
* \brief Forces Logger to echo everything to stdout if set to true. * \brief Forces Logger to log everything and echo to stdout if set to true.
*/ */
static void setEchoMode(bool enable); static void setDebugMode(bool enable);
private: private:
static void writeLog(const int priority, const char * format, va_list ap); static void writeLog(const int priority, const char * format, va_list ap);
//! True if the log is open //! True if the log is open
static bool m_isOpened; static bool m_isOpened;
//! Echo everything to stdout if true
static bool m_echoMode; //! Echo everything including debug messages to stdout if true
static bool m_debugMode;
}; };
#endif // LOGGER_H #endif // LOGGER_H

@ -28,24 +28,30 @@
#define DECL_EXPORT extern "C" __attribute__ ((__visibility__("default"))) #define DECL_EXPORT extern "C" __attribute__ ((__visibility__("default")))
//! Signal handler to reap zombie processes int g_sigChldPipeFd = -1;
void reapZombies(int) int g_sigTermPipeFd = -1;
int g_sigUsr1PipeFd = -1;
char g_dummyPipeData = 0;
static void sigChldHandler(int)
{ {
if (Daemon::instance()) write(g_sigChldPipeFd, &g_dummyPipeData, 1);
{ }
Daemon::instance()->reapZombies();
} static void sigTermHandler(int)
{
write(g_sigTermPipeFd, &g_dummyPipeData, 1);
} }
void exitLauncher(int) static void sigUsr1Handler(int)
{ {
exit(0); write(g_sigUsr1PipeFd, &g_dummyPipeData, 1);
} }
//! Main function //! Main function
DECL_EXPORT int main(int argc, char * argv[]) DECL_EXPORT int main(int argc, char * argv[])
{ {
// Open the log // Open the log
Logger::openLog(PROG_NAME_LAUNCHER); Logger::openLog(PROG_NAME_LAUNCHER);
Logger::logDebug("%s starting..", PROG_NAME_LAUNCHER); Logger::logDebug("%s starting..", PROG_NAME_LAUNCHER);
@ -56,13 +62,19 @@ DECL_EXPORT int main(int argc, char * argv[])
Logger::logErrorAndDie(EXIT_FAILURE, "%s is already running \n", PROG_NAME_LAUNCHER); Logger::logErrorAndDie(EXIT_FAILURE, "%s is already running \n", PROG_NAME_LAUNCHER);
} }
// Install signal handlers
signal(SIGCHLD, reapZombies);
signal(SIGTERM, exitLauncher);
// Create main daemon instance // Create main daemon instance
Daemon myDaemon(argc, argv); Daemon myDaemon(argc, argv);
// Get fd's for signal pipes.
g_sigChldPipeFd = myDaemon.sigChldPipeFd();
g_sigTermPipeFd = myDaemon.sigTermPipeFd();
g_sigUsr1PipeFd = myDaemon.sigUsr1PipeFd();
// Install signal handlers
signal(SIGCHLD, sigChldHandler); // reap zombies
signal(SIGTERM, sigTermHandler); // exit launcher
signal(SIGUSR1, sigUsr1Handler); // restore normal mode
// Run the main loop // Run the main loop
myDaemon.run(); myDaemon.run();
@ -71,4 +83,3 @@ DECL_EXPORT int main(int argc, char * argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

@ -41,6 +41,7 @@ bool MBooster::preload()
// an MApplication) // an MApplication)
MComponentCache::populateForMApplication(); MComponentCache::populateForMApplication();
#endif #endif
return true; return true;
} }
@ -66,26 +67,36 @@ char MBooster::type()
bool MBooster::receiveDataFromInvoker(int socketFd) bool MBooster::receiveDataFromInvoker(int socketFd)
{ {
// Setup the conversation channel with the invoker. // Use the default implementation if in boot mode
setConnection(new Connection(socketFd)); // (it won't require QApplication running).
EventHandler handler(this);
handler.runEventLoop();
// Receive application data from the invoker if (bootMode())
if(!connection()->receiveApplicationData(appData()))
{ {
connection()->close(); return Booster::receiveDataFromInvoker(socketFd);
return false;
} }
else
// Close the connection if exit status doesn't need
// to be sent back to invoker
if (!connection()->isReportAppExitStatusNeeded())
{ {
connection()->close(); // Setup the conversation channel with the invoker.
} setConnection(new Connection(socketFd));
return true; EventHandler handler(this);
handler.runEventLoop();
// Receive application data from the invoker
if(!connection()->receiveApplicationData(appData()))
{
connection()->close();
return false;
}
// Close the connection if exit status doesn't need
// to be sent back to invoker
if (!connection()->isReportAppExitStatusNeeded())
{
connection()->close();
}
return true;
}
} }

@ -47,9 +47,6 @@ public:
//! \brief Destructor //! \brief Destructor
virtual ~MBooster() {} virtual ~MBooster() {}
//! \reimp
virtual bool preload();
/*! /*!
* \brief Return the socket name common to all MBooster objects. * \brief Return the socket name common to all MBooster objects.
* \return Path to the socket file. * \return Path to the socket file.
@ -77,6 +74,9 @@ public:
protected: protected:
//! \reimp
virtual bool preload();
//! \reimp //! \reimp
virtual bool receiveDataFromInvoker(int socketFd); virtual bool receiveDataFromInvoker(int socketFd);

@ -58,11 +58,11 @@ public:
*/ */
static char type(); static char type();
protected:
//! \reimp //! \reimp
virtual bool preload(); virtual bool preload();
protected:
//! \reimp //! \reimp
virtual const string & socketId() const; virtual const string & socketId() const;

@ -6,5 +6,5 @@
# If the length of the application name with parameters is longer than space # If the length of the application name with parameters is longer than space
# available, parameters will be cut off. The main function will still always # available, parameters will be cut off. The main function will still always
# get the complete argument list. # get the complete argument list.
exec /usr/bin/applauncherd.bin " " exec /usr/bin/applauncherd.bin $@ " "

@ -30,6 +30,9 @@ public:
const std::string & socketId() const; const std::string & socketId() const;
const std::string & boosterTemporaryProcessName() const; const std::string & boosterTemporaryProcessName() const;
protected:
bool preload();
private: private:
const string m_socketId; const string m_socketId;
const string m_temporaryProcessName; const string m_temporaryProcessName;
@ -45,6 +48,11 @@ char MyBooster::boosterType() const
return 'x'; return 'x';
} }
bool MyBooster::preload()
{
return true;
}
const std::string & MyBooster::boosterTemporaryProcessName() const const std::string & MyBooster::boosterTemporaryProcessName() const
{ {
return m_temporaryProcessName; return m_temporaryProcessName;

Loading…
Cancel
Save