From e0fc09b439b66df0e35c159d0b5b055cde7d2792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 25 Jun 2015 08:59:51 +0200 Subject: [PATCH] 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). --- src/servers/launch/Conditions.cpp | 105 ++++++++++++++++++++ src/servers/launch/Conditions.h | 7 ++ src/servers/launch/Job.cpp | 16 --- src/servers/launch/Job.h | 4 - src/servers/launch/LaunchDaemon.cpp | 32 +++--- src/servers/launch/SettingsParser.cpp | 1 + src/tests/servers/launch/ConditionsTest.cpp | 43 ++++++++ 7 files changed, 176 insertions(+), 32 deletions(-) diff --git a/src/servers/launch/Conditions.cpp b/src/servers/launch/Conditions.cpp index 8cf3d924f6..d577a25483 100644 --- a/src/servers/launch/Conditions.cpp +++ b/src/servers/launch/Conditions.cpp @@ -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(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; +} diff --git a/src/servers/launch/Conditions.h b/src/servers/launch/Conditions.h index 3f779ff2a9..2414accb4b 100644 --- a/src/servers/launch/Conditions.h +++ b/src/servers/launch/Conditions.h @@ -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); }; diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp index 371e6007e8..093275746c 100644 --- a/src/servers/launch/Job.cpp +++ b/src/servers/launch/Job.cpp @@ -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 { diff --git a/src/servers/launch/Job.h b/src/servers/launch/Job.h index efea7fe680..3b868b499b 100644 --- a/src/servers/launch/Job.h +++ b/src/servers/launch/Job.h @@ -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; diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index fb2d9bef23..63b2ebb5ae 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -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 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 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); } diff --git a/src/servers/launch/SettingsParser.cpp b/src/servers/launch/SettingsParser.cpp index 083993d4fa..3606de0ff5 100644 --- a/src/servers/launch/SettingsParser.cpp +++ b/src/servers/launch/SettingsParser.cpp @@ -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} diff --git a/src/tests/servers/launch/ConditionsTest.cpp b/src/tests/servers/launch/ConditionsTest.cpp index 0f483821a8..d6ff3296b8 100644 --- a/src/tests/servers/launch/ConditionsTest.cpp +++ b/src/tests/servers/launch/ConditionsTest.cpp @@ -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)); }