launch_daemon: Monitor teams, and restart services.
* Services that end are now automatically restarted. * However, this is very basic at the moment, there is no throttling, and no support for shutting down the system.
This commit is contained in:
@@ -81,6 +81,20 @@ Job::~Job()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::TeamRegistrator*
|
||||||
|
Job::TeamRegistrator() const
|
||||||
|
{
|
||||||
|
return fTeamRegistrator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Job::SetTeamRegistrator(::TeamRegistrator* registrator)
|
||||||
|
{
|
||||||
|
fTeamRegistrator = registrator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Job::IsEnabled() const
|
Job::IsEnabled() const
|
||||||
{
|
{
|
||||||
@@ -349,8 +363,24 @@ Job::IsLaunched() const
|
|||||||
bool
|
bool
|
||||||
Job::IsRunning() const
|
Job::IsRunning() const
|
||||||
{
|
{
|
||||||
// TODO: monitor team status; should jobs be allowed to run multiple times?
|
return fTeam >= 0;
|
||||||
return State() == B_JOB_STATE_SUCCEEDED && IsLaunched() && IsService();
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Job::TeamDeleted()
|
||||||
|
{
|
||||||
|
fTeam = -1;
|
||||||
|
if (IsService())
|
||||||
|
SetState(B_JOB_STATE_WAITING_TO_RUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Job::CanBeLaunched() const
|
||||||
|
{
|
||||||
|
// Services cannot be launched while they are running
|
||||||
|
return !IsLaunching() && (!IsService() || !IsRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -384,7 +414,7 @@ Job::Run()
|
|||||||
{
|
{
|
||||||
status_t status = BJob::Run();
|
status_t status = BJob::Run();
|
||||||
|
|
||||||
// TODO: monitor team, don't just do this
|
// Jobs can be relaunched at any time
|
||||||
if (!IsService())
|
if (!IsService())
|
||||||
SetState(B_JOB_STATE_WAITING_TO_RUN);
|
SetState(B_JOB_STATE_WAITING_TO_RUN);
|
||||||
|
|
||||||
@@ -396,8 +426,10 @@ status_t
|
|||||||
Job::Execute()
|
Job::Execute()
|
||||||
{
|
{
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
if (!IsLaunched() || !IsService())
|
if (!IsRunning() || !IsService())
|
||||||
status = Launch();
|
status = Launch();
|
||||||
|
else
|
||||||
|
debug_printf("Ignore launching %s\n", Name());
|
||||||
|
|
||||||
fLaunching = false;
|
fLaunching = false;
|
||||||
return status;
|
return status;
|
||||||
@@ -460,6 +492,9 @@ Job::_SetLaunchStatus(status_t launchStatus)
|
|||||||
fLaunchStatus = launchStatus != B_NO_INIT ? launchStatus : B_ERROR;
|
fLaunchStatus = launchStatus != B_NO_INIT ? launchStatus : B_ERROR;
|
||||||
launchLocker.Unlock();
|
launchLocker.Unlock();
|
||||||
|
|
||||||
|
if (fTeamRegistrator != NULL)
|
||||||
|
fTeamRegistrator->RegisterTeam(this);
|
||||||
|
|
||||||
_SendPendingLaunchDataReplies();
|
_SendPendingLaunchDataReplies();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using namespace BSupportKit;
|
|||||||
class BMessage;
|
class BMessage;
|
||||||
|
|
||||||
class Finder;
|
class Finder;
|
||||||
|
class Job;
|
||||||
class Target;
|
class Target;
|
||||||
|
|
||||||
struct entry_ref;
|
struct entry_ref;
|
||||||
@@ -30,12 +31,22 @@ struct entry_ref;
|
|||||||
typedef std::map<BString, BMessage> PortMap;
|
typedef std::map<BString, BMessage> PortMap;
|
||||||
|
|
||||||
|
|
||||||
|
class TeamRegistrator {
|
||||||
|
public:
|
||||||
|
virtual void RegisterTeam(Job* job) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Job : public BaseJob {
|
class Job : public BaseJob {
|
||||||
public:
|
public:
|
||||||
Job(const char* name);
|
Job(const char* name);
|
||||||
Job(const Job& other);
|
Job(const Job& other);
|
||||||
virtual ~Job();
|
virtual ~Job();
|
||||||
|
|
||||||
|
::TeamRegistrator* TeamRegistrator() const;
|
||||||
|
void SetTeamRegistrator(
|
||||||
|
::TeamRegistrator* registrator);
|
||||||
|
|
||||||
bool IsEnabled() const;
|
bool IsEnabled() const;
|
||||||
void SetEnabled(bool enable);
|
void SetEnabled(bool enable);
|
||||||
|
|
||||||
@@ -72,6 +83,8 @@ public:
|
|||||||
status_t Launch();
|
status_t Launch();
|
||||||
bool IsLaunched() const;
|
bool IsLaunched() const;
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
|
void TeamDeleted();
|
||||||
|
bool CanBeLaunched() const;
|
||||||
|
|
||||||
bool IsLaunching() const;
|
bool IsLaunching() const;
|
||||||
void SetLaunching(bool launching);
|
void SetLaunching(bool launching);
|
||||||
@@ -117,6 +130,7 @@ private:
|
|||||||
::Condition* fCondition;
|
::Condition* fCondition;
|
||||||
BObjectList<BMessage>
|
BObjectList<BMessage>
|
||||||
fPendingLaunchDataReplies;
|
fPendingLaunchDataReplies;
|
||||||
|
::TeamRegistrator* fTeamRegistrator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,11 @@
|
|||||||
#include <AppMisc.h>
|
#include <AppMisc.h>
|
||||||
#include <LaunchDaemonDefs.h>
|
#include <LaunchDaemonDefs.h>
|
||||||
#include <LaunchRosterPrivate.h>
|
#include <LaunchRosterPrivate.h>
|
||||||
|
#include <locks.h>
|
||||||
|
#include <MessengerPrivate.h>
|
||||||
#include <RosterPrivate.h>
|
#include <RosterPrivate.h>
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
|
#include <system_info.h>
|
||||||
|
|
||||||
#include "multiuser_utils.h"
|
#include "multiuser_utils.h"
|
||||||
|
|
||||||
@@ -116,10 +119,11 @@ typedef std::map<BString, Job*> JobMap;
|
|||||||
typedef std::map<uid_t, Session*> SessionMap;
|
typedef std::map<uid_t, Session*> SessionMap;
|
||||||
typedef std::map<BString, Target*> TargetMap;
|
typedef std::map<BString, Target*> TargetMap;
|
||||||
typedef std::map<BString, ExternalEventSource*> EventMap;
|
typedef std::map<BString, ExternalEventSource*> EventMap;
|
||||||
|
typedef std::map<team_id, Job*> TeamMap;
|
||||||
|
|
||||||
|
|
||||||
class LaunchDaemon : public BServer, public Finder, public ConditionContext,
|
class LaunchDaemon : public BServer, public Finder, public ConditionContext,
|
||||||
public EventRegistrator {
|
public EventRegistrator, public TeamRegistrator {
|
||||||
public:
|
public:
|
||||||
LaunchDaemon(bool userMode,
|
LaunchDaemon(bool userMode,
|
||||||
const EventMap& events, status_t& error);
|
const EventMap& events, status_t& error);
|
||||||
@@ -140,6 +144,9 @@ public:
|
|||||||
virtual void UnregisterExternalEvent(Event* event,
|
virtual void UnregisterExternalEvent(Event* event,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
|
||||||
|
// TeamRegistrator
|
||||||
|
virtual void RegisterTeam(Job* job);
|
||||||
|
|
||||||
virtual void ReadyToRun();
|
virtual void ReadyToRun();
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
@@ -208,6 +215,8 @@ private:
|
|||||||
SessionMap fSessions;
|
SessionMap fSessions;
|
||||||
MainWorker* fMainWorker;
|
MainWorker* fMainWorker;
|
||||||
Target* fInitTarget;
|
Target* fInitTarget;
|
||||||
|
TeamMap fTeams;
|
||||||
|
mutex fTeamsLock;
|
||||||
bool fSafeMode;
|
bool fSafeMode;
|
||||||
bool fReadOnlyBootVolume;
|
bool fReadOnlyBootVolume;
|
||||||
bool fUserMode;
|
bool fUserMode;
|
||||||
@@ -305,6 +314,8 @@ LaunchDaemon::LaunchDaemon(bool userMode, const EventMap& events,
|
|||||||
fInitTarget(userMode ? NULL : new Target("init")),
|
fInitTarget(userMode ? NULL : new Target("init")),
|
||||||
fUserMode(userMode)
|
fUserMode(userMode)
|
||||||
{
|
{
|
||||||
|
mutex_init(&fTeamsLock, "teams lock");
|
||||||
|
|
||||||
fMainWorker = new MainWorker(fJobQueue);
|
fMainWorker = new MainWorker(fJobQueue);
|
||||||
fMainWorker->Init();
|
fMainWorker->Init();
|
||||||
|
|
||||||
@@ -391,6 +402,14 @@ LaunchDaemon::UnregisterExternalEvent(Event* event, const char* name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::RegisterTeam(Job* job)
|
||||||
|
{
|
||||||
|
MutexLocker locker(fTeamsLock);
|
||||||
|
fTeams.insert(std::make_pair(job->Team(), job));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LaunchDaemon::ReadyToRun()
|
LaunchDaemon::ReadyToRun()
|
||||||
{
|
{
|
||||||
@@ -429,6 +448,12 @@ LaunchDaemon::ReadyToRun()
|
|||||||
fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths);
|
fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths);
|
||||||
_ReadPaths(paths);
|
_ReadPaths(paths);
|
||||||
|
|
||||||
|
BMessenger target(this);
|
||||||
|
BMessenger::Private messengerPrivate(target);
|
||||||
|
port_id port = messengerPrivate.Port();
|
||||||
|
int32 token = messengerPrivate.Token();
|
||||||
|
__start_watching_system(-1, B_WATCH_SYSTEM_TEAM_DELETION, port, token);
|
||||||
|
|
||||||
_InitJobs(NULL);
|
_InitJobs(NULL);
|
||||||
_LaunchJobs(NULL);
|
_LaunchJobs(NULL);
|
||||||
|
|
||||||
@@ -445,6 +470,30 @@ void
|
|||||||
LaunchDaemon::MessageReceived(BMessage* message)
|
LaunchDaemon::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
switch (message->what) {
|
switch (message->what) {
|
||||||
|
case B_SYSTEM_OBJECT_UPDATE:
|
||||||
|
{
|
||||||
|
int32 opcode = message->GetInt32("opcode", 0);
|
||||||
|
team_id team = (team_id)message->GetInt32("team", -1);
|
||||||
|
if (opcode != B_TEAM_DELETED || team < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
MutexLocker locker(fTeamsLock);
|
||||||
|
|
||||||
|
TeamMap::iterator found = fTeams.find(team);
|
||||||
|
if (found != fTeams.end()) {
|
||||||
|
Job* job = found->second;
|
||||||
|
TRACE("Job %s ended!\n", job->Name());
|
||||||
|
job->TeamDeleted();
|
||||||
|
|
||||||
|
if (job->IsService()) {
|
||||||
|
// TODO: take restart throttle into account
|
||||||
|
// TODO: don't restart on shutdown
|
||||||
|
_LaunchJob(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case B_GET_LAUNCH_DATA:
|
case B_GET_LAUNCH_DATA:
|
||||||
_HandleGetLaunchData(message);
|
_HandleGetLaunchData(message);
|
||||||
break;
|
break;
|
||||||
@@ -1112,6 +1161,7 @@ LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message)
|
|||||||
if (job == NULL)
|
if (job == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
job->SetTeamRegistrator(this);
|
||||||
job->SetService(service);
|
job->SetService(service);
|
||||||
job->SetCreateDefaultPort(service);
|
job->SetCreateDefaultPort(service);
|
||||||
job->SetTarget(target);
|
job->SetTarget(target);
|
||||||
@@ -1232,7 +1282,7 @@ LaunchDaemon::_LaunchJobs(Target* target, bool forceNow)
|
|||||||
void
|
void
|
||||||
LaunchDaemon::_LaunchJob(Job* job, uint32 options)
|
LaunchDaemon::_LaunchJob(Job* job, uint32 options)
|
||||||
{
|
{
|
||||||
if (job == NULL || job->IsLaunching() || job->IsRunning()
|
if (job == NULL || !job->CanBeLaunched()
|
||||||
|| ((options & FORCE_NOW) == 0
|
|| ((options & FORCE_NOW) == 0
|
||||||
&& (!job->EventHasTriggered() || !job->CheckCondition(*this)
|
&& (!job->EventHasTriggered() || !job->CheckCondition(*this)
|
||||||
|| ((options & TRIGGER_DEMAND) != 0
|
|| ((options & TRIGGER_DEMAND) != 0
|
||||||
@@ -1256,7 +1306,12 @@ LaunchDaemon::_LaunchJob(Job* job, uint32 options)
|
|||||||
job->Event()->ResetTrigger();
|
job->Event()->ResetTrigger();
|
||||||
|
|
||||||
job->SetLaunching(true);
|
job->SetLaunching(true);
|
||||||
fJobQueue.AddJob(job);
|
|
||||||
|
status_t status = fJobQueue.AddJob(job);
|
||||||
|
if (status != B_OK) {
|
||||||
|
debug_printf("Adding job %s to queue failed: %s\n", job->Name(),
|
||||||
|
strerror(status));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1532,7 +1587,11 @@ LaunchDaemon::_AddInitJob(BJob* job)
|
|||||||
static void
|
static void
|
||||||
open_stdio(int targetFD, int openMode)
|
open_stdio(int targetFD, int openMode)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
int fd = open("/dev/dprintf", openMode);
|
||||||
|
#else
|
||||||
int fd = open("/dev/null", openMode);
|
int fd = open("/dev/null", openMode);
|
||||||
|
#endif
|
||||||
if (fd != targetFD) {
|
if (fd != targetFD) {
|
||||||
dup2(fd, targetFD);
|
dup2(fd, targetFD);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|||||||
Reference in New Issue
Block a user