From 2ca4f3f81d28b528d479f95e29cf6f936e2c7dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 17 Jul 2015 22:59:17 +0200 Subject: [PATCH] launch_daemon: Jobs were started before their target. * A job must not be launched when its target hasn't been launched yet. This fixes Tracker launching when the mount_server scanned the initial disk, even though the FirstBootPrompt was showing. * Jobs are no longer initialized when their target has not been launched yet. This also means that you cannot talk to a service beforehand in this case. * Slight refactoring and clarifying, even added some documentation :-) * _TriggerJob() is now called _LaunchJob(), and does all the checks for jobs that _LaunchJobs() does now for targets. --- src/servers/launch/BaseJob.cpp | 7 ++- src/servers/launch/BaseJob.h | 2 +- src/servers/launch/Events.cpp | 9 ++- src/servers/launch/Job.cpp | 14 +++++ src/servers/launch/Job.h | 2 + src/servers/launch/LaunchDaemon.cpp | 89 +++++++++++++++++------------ src/servers/launch/Target.cpp | 10 +++- src/servers/launch/Target.h | 5 ++ 8 files changed, 98 insertions(+), 40 deletions(-) diff --git a/src/servers/launch/BaseJob.cpp b/src/servers/launch/BaseJob.cpp index fd11fdc41d..555375e3a9 100644 --- a/src/servers/launch/BaseJob.cpp +++ b/src/servers/launch/BaseJob.cpp @@ -93,10 +93,15 @@ BaseJob::SetEvent(::Event* event) } +/*! Determines whether the events of this job has been triggered + already or not. + Note, if this job does not have any events, this method returns + \c true. +*/ bool BaseJob::EventHasTriggered() const { - return Event() != NULL && Event()->Triggered(); + return Event() == NULL || Event()->Triggered(); } diff --git a/src/servers/launch/BaseJob.h b/src/servers/launch/BaseJob.h index 41d38f07a2..26df36a284 100644 --- a/src/servers/launch/BaseJob.h +++ b/src/servers/launch/BaseJob.h @@ -28,7 +28,7 @@ public: const ::Condition* Condition() const; ::Condition* Condition(); void SetCondition(::Condition* condition); - bool CheckCondition(ConditionContext& context) const; + virtual bool CheckCondition(ConditionContext& context) const; const ::Event* Event() const; ::Event* Event(); diff --git a/src/servers/launch/Events.cpp b/src/servers/launch/Events.cpp index 8b46df3a02..6642f66639 100644 --- a/src/servers/launch/Events.cpp +++ b/src/servers/launch/Events.cpp @@ -539,10 +539,15 @@ Events::TriggerRegisteredEvent(Event* event, const char* name) } +/*! This will trigger a demand event, if it exists. + + \return \c true, if there is a demand event, and it has been + triggered by this call. \c false if not. +*/ /*static*/ bool Events::TriggerDemand(Event* event) { - if (event == NULL) + if (event == NULL || event->Triggered()) return false; if (EventContainer* container = dynamic_cast(event)) { @@ -551,7 +556,7 @@ Events::TriggerDemand(Event* event) Event* childEvent = container->Events().ItemAt(index); if (dynamic_cast(childEvent) != NULL) { childEvent->Trigger(); - return true; + break; } if (dynamic_cast(childEvent) != NULL) { if (TriggerDemand(childEvent)) diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp index 1092ae9cd4..224a17ef25 100644 --- a/src/servers/launch/Job.cpp +++ b/src/servers/launch/Job.cpp @@ -41,6 +41,10 @@ Job::Job(const Job& other) fTarget(other.Target()) { fCondition = other.fCondition; + // TODO: copy events + //fEvent = other.fEvent; + fEnvironment = other.fEnvironment; + fSourceFiles = other.fSourceFiles; for (int32 i = 0; i < other.Arguments().CountStrings(); i++) AddArgument(other.Arguments().StringAt(i)); @@ -172,6 +176,16 @@ Job::AddRequirement(const char* requirement) } +bool +Job::CheckCondition(ConditionContext& context) const +{ + if (Target() != NULL && !Target()->HasLaunched()) + return false; + + return BaseJob::CheckCondition(context); +} + + status_t Job::Init(const Finder& finder, std::set& dependencies) { diff --git a/src/servers/launch/Job.h b/src/servers/launch/Job.h index 0adc504a3d..e2ee0b4d0f 100644 --- a/src/servers/launch/Job.h +++ b/src/servers/launch/Job.h @@ -54,6 +54,8 @@ public: BStringList& Requirements(); void AddRequirement(const char* requirement); + virtual bool CheckCondition(ConditionContext& context) const; + status_t Init(const Finder& jobs, std::set& dependencies); status_t InitCheck() const; diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 095fe14f1a..2d59a4ce69 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -134,10 +134,10 @@ private: const char* name); void _AddJob(Target* target, bool service, BMessage& message); - void _InitJobs(); - void _LaunchJobs(Target* target); - void _TriggerJob(Job* job); - void _AddLaunchJob(Job* job); + void _InitJobs(Target* target); + void _LaunchJobs(Target* target, + bool forceNow = false); + void _LaunchJob(Job* job, bool forceNow = false); void _AddTarget(Target* target); void _SetCondition(BaseJob* job, const BMessage& message); @@ -361,7 +361,7 @@ LaunchDaemon::ReadyToRun() fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths); _ReadPaths(paths); - _InitJobs(); + _InitJobs(NULL); _LaunchJobs(NULL); // Launch run targets (ignores events) @@ -414,13 +414,13 @@ LaunchDaemon::MessageReceived(BMessage* message) break; Job* job = FindJob(name); - if (job != NULL && job->EventHasTriggered()) { - _TriggerJob(job); + if (job != NULL) { + _LaunchJob(job); break; } Target* target = FindTarget(name); - if (target != NULL && target->EventHasTriggered()) { + if (target != NULL) { _LaunchJobs(target); break; } @@ -442,7 +442,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message) return; BMessage reply((uint32)B_OK); - bool triggerJob = true; + bool launchJob = true; Job* job = FindJob(get_leaf(message->GetString("name"))); if (job == NULL) { @@ -454,7 +454,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message) } reply.what = B_NAME_NOT_FOUND; } else if (!job->IsLaunched()) { - if (!job->CheckCondition(*this)) { + if (job->InitCheck() == B_NO_INIT || !job->CheckCondition(*this)) { // The job exists, but cannot be started yet, as its // conditions are not met; don't make it available yet // TODO: we may not want to initialize jobs with conditions @@ -465,9 +465,8 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message) // The job is not triggered by demand; we cannot start it now reply.what = B_NO_INIT; } else { - // The job has already been triggered, don't trigger it - // again - triggerJob = false; + // The job has already been triggered, don't launch it again + launchJob = false; } } } @@ -490,8 +489,9 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message) iterator->second.GetInt32("port", -1)); } - if (triggerJob) - _TriggerJob(job); + // Launch the job if it hasn't been launched already + if (launchJob) + _LaunchJob(job); } message->SendReply(&reply); } @@ -932,13 +932,20 @@ LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message) } +/*! Initializes all jobs for the specified target (may be \c NULL). + Jobs that cannot be initialized, and those that never will be due to + conditions, will be removed from the list. +*/ void -LaunchDaemon::_InitJobs() +LaunchDaemon::_InitJobs(Target* target) { for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();) { Job* job = iterator->second; JobMap::iterator remove = iterator++; + if (job->Target() != target) + continue; + status_t status = B_NO_INIT; if (job->IsEnabled()) { // Filter out jobs that have a constant and failing condition @@ -965,52 +972,64 @@ LaunchDaemon::_InitJobs() /*! Adds all jobs for the specified target (may be \c NULL) to the launch - queue, except those that are triggered by events. + queue, except those that are triggered by events that haven't been + triggered yet. + + Unless \a forceNow is true, the target is only launched if its events, + if any, have been triggered already, and its conditions are met. */ void -LaunchDaemon::_LaunchJobs(Target* target) +LaunchDaemon::_LaunchJobs(Target* target, bool forceNow) { - if (target != NULL && !target->CheckCondition(*this)) + if (!forceNow && target != NULL && (!target->EventHasTriggered() + || !target->CheckCondition(*this))) { return; + } + + if (target != NULL && !target->HasLaunched()) { + target->SetLaunched(true); + _InitJobs(target); + } for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end(); iterator++) { Job* job = iterator->second; - if (job->Target() == target - && (job->Event() == NULL || job->Event()->Triggered())) - _TriggerJob(job); + if (job->Target() == target) + _LaunchJob(job); } } +/*! Adds the specified \a job to the launch queue + queue, except those that are triggered by events. + + Unless \a forceNow is true, the target is only launched if its events, + if any, have been triggered already. + + Calling this method will trigger a demand event. +*/ void -LaunchDaemon::_TriggerJob(Job* job) +LaunchDaemon::_LaunchJob(Job* job, bool forceNow) { - if (job == NULL) + if (job == NULL || job->IsLaunched() || !forceNow + && (!job->EventHasTriggered() || !job->CheckCondition(*this) + || Events::TriggerDemand(job->Event()))) { return; + } int32 count = job->Requirements().CountStrings(); for (int32 index = 0; index < count; index++) { Job* requirement = FindJob(job->Requirements().StringAt(index)); if (requirement != NULL) - _TriggerJob(requirement); + _LaunchJob(requirement); } - if (job->EventHasTriggered() || !Events::TriggerDemand(job->Event())) - _AddLaunchJob(job); -} - - -void -LaunchDaemon::_AddLaunchJob(Job* job) -{ if (job->Target() != NULL) job->Target()->ResolveSourceFiles(); if (job->Event() != NULL) job->Event()->ResetTrigger(); - if (!job->IsLaunched() && job->CheckCondition(*this)) - fJobQueue.AddJob(job); + fJobQueue.AddJob(job); } diff --git a/src/servers/launch/Target.cpp b/src/servers/launch/Target.cpp index 34bd13317e..91e09e726c 100644 --- a/src/servers/launch/Target.cpp +++ b/src/servers/launch/Target.cpp @@ -9,7 +9,8 @@ Target::Target(const char* name) : - BaseJob(name) + BaseJob(name), + fLaunched(false) { } @@ -21,6 +22,13 @@ Target::AddData(const char* name, BMessage& data) } +void +Target::SetLaunched(bool launched) +{ + fLaunched = launched; +} + + status_t Target::Execute() { diff --git a/src/servers/launch/Target.h b/src/servers/launch/Target.h index 0b4b37d497..0d0ece0a17 100644 --- a/src/servers/launch/Target.h +++ b/src/servers/launch/Target.h @@ -22,11 +22,16 @@ public: const BMessage& Data() const { return fData; } + bool HasLaunched() const + { return fLaunched; } + void SetLaunched(bool launched); + protected: virtual status_t Execute(); private: BMessage fData; + bool fLaunched; };