launch_daemon: Conditions now know if they are constant.

* This allows to remove a job in the init phase already, if its
  condition is not only constant, but also failing.
* Also removed the special Job::LaunchInSafeMode() method; this is now
  done using the conditions (the config option no_safemode remains,
  though).
This commit is contained in:
Axel Dörfler 2015-06-25 08:59:51 +02:00
parent 004cd6709d
commit e0fc09b439
7 changed files with 176 additions and 32 deletions

View File

@ -21,9 +21,13 @@
class ConditionContainer : public Condition {
protected:
ConditionContainer(const BMessage& args);
ConditionContainer();
public:
void AddCondition(Condition* condition);
virtual bool IsConstant(ConditionContext& context) const;
protected:
void ToString(BString& string) const;
@ -35,6 +39,7 @@ protected:
class AndCondition : public ConditionContainer {
public:
AndCondition(const BMessage& args);
AndCondition();
virtual bool Test(ConditionContext& context) const;
virtual BString ToString() const;
@ -46,6 +51,8 @@ public:
OrCondition(const BMessage& args);
virtual bool Test(ConditionContext& context) const;
virtual bool IsConstant(ConditionContext& context) const;
virtual BString ToString() const;
};
@ -53,6 +60,7 @@ public:
class NotCondition : public ConditionContainer {
public:
NotCondition(const BMessage& args);
NotCondition();
virtual bool Test(ConditionContext& context) const;
virtual BString ToString() const;
@ -62,6 +70,8 @@ public:
class SafeModeCondition : public Condition {
public:
virtual bool Test(ConditionContext& context) const;
virtual bool IsConstant(ConditionContext& context) const;
virtual BString ToString() const;
};
@ -71,6 +81,8 @@ public:
ReadOnlyCondition(const BMessage& args);
virtual bool Test(ConditionContext& context) const;
virtual bool IsConstant(ConditionContext& context) const;
virtual BString ToString() const;
private:
@ -124,6 +136,13 @@ Condition::~Condition()
}
bool
Condition::IsConstant(ConditionContext& context) const
{
return false;
}
// #pragma mark -
@ -145,6 +164,13 @@ ConditionContainer::ConditionContainer(const BMessage& args)
}
ConditionContainer::ConditionContainer()
:
fConditions(10, true)
{
}
void
ConditionContainer::AddCondition(Condition* condition)
{
@ -153,6 +179,25 @@ ConditionContainer::AddCondition(Condition* condition)
}
/*! A single constant failing condition makes this constant, too, otherwise,
a single non-constant condition makes this non-constant as well.
*/
bool
ConditionContainer::IsConstant(ConditionContext& context) const
{
bool fixed = true;
for (int32 index = 0; index < fConditions.CountItems(); index++) {
const Condition* condition = fConditions.ItemAt(index);
if (condition->IsConstant(context)) {
if (!condition->Test(context))
return true;
} else
fixed = false;
}
return fixed;
}
void
ConditionContainer::ToString(BString& string) const
{
@ -177,6 +222,11 @@ AndCondition::AndCondition(const BMessage& args)
}
AndCondition::AndCondition()
{
}
bool
AndCondition::Test(ConditionContext& context) const
{
@ -223,6 +273,25 @@ OrCondition::Test(ConditionContext& context) const
}
/*! If there is a single succeeding constant condition, this is constant, too.
Otherwise, it is non-constant if there is a single non-constant condition.
*/
bool
OrCondition::IsConstant(ConditionContext& context) const
{
bool fixed = true;
for (int32 index = 0; index < fConditions.CountItems(); index++) {
const Condition* condition = fConditions.ItemAt(index);
if (condition->IsConstant(context)) {
if (condition->Test(context))
return true;
} else
fixed = false;
}
return fixed;
}
BString
OrCondition::ToString() const
{
@ -242,6 +311,11 @@ NotCondition::NotCondition(const BMessage& args)
}
NotCondition::NotCondition()
{
}
bool
NotCondition::Test(ConditionContext& context) const
{
@ -273,6 +347,13 @@ SafeModeCondition::Test(ConditionContext& context) const
}
bool
SafeModeCondition::IsConstant(ConditionContext& context) const
{
return true;
}
BString
SafeModeCondition::ToString() const
{
@ -314,6 +395,13 @@ ReadOnlyCondition::Test(ConditionContext& context) const
}
bool
ReadOnlyCondition::IsConstant(ConditionContext& context) const
{
return true;
}
BString
ReadOnlyCondition::ToString() const
{
@ -370,3 +458,20 @@ Conditions::FromMessage(const BMessage& message)
{
return create_condition("and", message);
}
/*static*/ Condition*
Conditions::AddNotSafeMode(Condition* condition)
{
AndCondition* and = dynamic_cast<AndCondition*>(condition);
if (and == NULL)
and = new AndCondition();
if (and != condition && condition != NULL)
and->AddCondition(condition);
NotCondition* not = new NotCondition();
not->AddCondition(new SafeModeCondition());
and->AddCondition(not);
return and;
}

View File

@ -24,6 +24,12 @@ public:
virtual ~Condition();
virtual bool Test(ConditionContext& context) const = 0;
/*! Determines whether or not the result of this condition is fixed,
and will not change anymore.
*/
virtual bool IsConstant(ConditionContext& context) const;
virtual BString ToString() const = 0;
};
@ -31,6 +37,7 @@ public:
class Conditions {
public:
static Condition* FromMessage(const BMessage& message);
static Condition* AddNotSafeMode(Condition* condition);
};

View File

@ -20,7 +20,6 @@ Job::Job(const char* name)
fEnabled(true),
fService(false),
fCreateDefaultPort(false),
fLaunchInSafeMode(true),
fInitStatus(B_NO_INIT),
fTeam(-1),
fTarget(NULL)
@ -34,7 +33,6 @@ Job::Job(const Job& other)
fEnabled(other.IsEnabled()),
fService(other.IsService()),
fCreateDefaultPort(other.CreateDefaultPort()),
fLaunchInSafeMode(other.LaunchInSafeMode()),
fInitStatus(B_NO_INIT),
fTeam(-1),
fTarget(other.Target())
@ -115,20 +113,6 @@ Job::AddPort(BMessage& data)
}
bool
Job::LaunchInSafeMode() const
{
return fLaunchInSafeMode;
}
void
Job::SetLaunchInSafeMode(bool launch)
{
fLaunchInSafeMode = launch;
}
const BStringList&
Job::Arguments() const
{

View File

@ -42,9 +42,6 @@ public:
void AddPort(BMessage& data);
bool LaunchInSafeMode() const;
void SetLaunchInSafeMode(bool launch);
const BStringList& Arguments() const;
BStringList& Arguments();
void AddArgument(const char* argument);
@ -82,7 +79,6 @@ private:
bool fEnabled;
bool fService;
bool fCreateDefaultPort;
bool fLaunchInSafeMode;
PortMap fPortMap;
status_t fInitStatus;
team_id fTeam;

View File

@ -102,7 +102,8 @@ private:
void _LaunchJobs(Target* target);
void _AddLaunchJob(Job* job);
void _AddTarget(Target* target);
void _SetCondition(BaseJob* job, BMessage& message);
void _SetCondition(BaseJob* job,
const BMessage& message);
status_t _StartSession(const char* login,
const char* password);
@ -589,8 +590,6 @@ LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message)
job->SetEnabled(!message.GetBool("disabled", !job->IsEnabled()));
job->SetService(service);
job->SetCreateDefaultPort(!message.GetBool("legacy", !service));
job->SetLaunchInSafeMode(
!message.GetBool("no_safemode", !job->LaunchInSafeMode()));
job->SetTarget(target);
_SetCondition(job, message);
@ -628,9 +627,13 @@ LaunchDaemon::_InitJobs()
JobMap::iterator remove = iterator++;
status_t status = B_NO_INIT;
if (job->IsEnabled() && (!IsSafeMode() || job->LaunchInSafeMode())) {
std::set<BString> dependencies;
status = job->Init(*this, dependencies);
if (job->IsEnabled()) {
// Filter out jobs that have a constant and failing condition
if (job->Condition() == NULL || !job->Condition()->IsConstant(*this)
|| job->Condition()->Test(*this)) {
std::set<BString> dependencies;
status = job->Init(*this, dependencies);
}
}
if (status != B_OK) {
@ -679,14 +682,19 @@ LaunchDaemon::_AddTarget(Target* target)
void
LaunchDaemon::_SetCondition(BaseJob* job, BMessage& message)
LaunchDaemon::_SetCondition(BaseJob* job, const BMessage& message)
{
Condition* condition = NULL;
BMessage conditions;
if (message.FindMessage("if", &conditions) == B_OK) {
Condition* condition = Conditions::FromMessage(conditions);
if (condition != NULL)
job->SetCondition(condition);
}
if (message.FindMessage("if", &conditions) == B_OK)
condition = Conditions::FromMessage(conditions);
if (message.GetBool("no_safemode"))
condition = Conditions::AddNotSafeMode(condition);
if (condition != NULL)
job->SetCondition(condition);
}

View File

@ -126,6 +126,7 @@ const static settings_template kTargetTemplate[] = {
{B_STRING_TYPE, "name", NULL, true},
{B_BOOL_TYPE, "reset", NULL},
{B_MESSAGE_TYPE, "if", kConditionTemplate},
{B_BOOL_TYPE, "no_safemode", NULL},
{B_MESSAGE_TYPE, "job", kJobTemplate},
{B_MESSAGE_TYPE, "service", kJobTemplate},
{0, NULL, NULL}

View File

@ -43,6 +43,7 @@ ConditionsTest::TestSafemode()
{
Condition* condition = _Condition("safemode");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(condition->IsConstant(sConditionContext));
class SafemodeConditionContext : public ConditionContext {
public:
@ -52,6 +53,7 @@ ConditionsTest::TestSafemode()
}
} safemodeContext;
CPPUNIT_ASSERT(condition->Test(safemodeContext));
CPPUNIT_ASSERT(condition->IsConstant(safemodeContext));
}
@ -60,6 +62,7 @@ ConditionsTest::TestFileExists()
{
Condition* condition = _Condition("file_exists /boot");
CPPUNIT_ASSERT(condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("file_exists /boot/don't fool me!");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
@ -73,17 +76,34 @@ ConditionsTest::TestOr()
"file_exists /boot\n"
"}\n");
CPPUNIT_ASSERT(condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("or {\n"
"file_exists /nowhere\n"
"}\n");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("or {\n"
"file_exists /boot\n"
"file_exists /nowhere\n"
"}\n");
CPPUNIT_ASSERT(condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("or {\n"
"not safemode\n"
"file_exists /boot\n"
"}\n");
CPPUNIT_ASSERT(condition->Test(sConditionContext));
CPPUNIT_ASSERT(condition->IsConstant(sConditionContext));
condition = _Condition("or {\n"
"safemode\n"
"file_exists /boot\n"
"}\n");
CPPUNIT_ASSERT(condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
}
@ -94,17 +114,40 @@ ConditionsTest::TestAnd()
"file_exists /boot\n"
"}\n");
CPPUNIT_ASSERT(condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("and {\n"
"file_exists /nowhere\n"
"}\n");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("and {\n"
"file_exists /boot\n"
"file_exists /nowhere\n"
"}\n");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("and {\n"
"safemode\n"
"file_exists /nowhere\n"
"}\n");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(condition->IsConstant(sConditionContext));
condition = _Condition("and {\n"
"not safemode\n"
"file_exists /nowhere\n"
"}\n");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(!condition->IsConstant(sConditionContext));
condition = _Condition("and {\n"
"safemode\n"
"}\n");
CPPUNIT_ASSERT(!condition->Test(sConditionContext));
CPPUNIT_ASSERT(condition->IsConstant(sConditionContext));
}