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.
This commit is contained in:
Axel Dörfler
2015-07-22 20:45:47 +02:00
parent 65ed8a5e87
commit 2ca4f3f81d
8 changed files with 98 additions and 40 deletions
+6 -1
View File
@@ -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 bool
BaseJob::EventHasTriggered() const BaseJob::EventHasTriggered() const
{ {
return Event() != NULL && Event()->Triggered(); return Event() == NULL || Event()->Triggered();
} }
+1 -1
View File
@@ -28,7 +28,7 @@ public:
const ::Condition* Condition() const; const ::Condition* Condition() const;
::Condition* Condition(); ::Condition* Condition();
void SetCondition(::Condition* condition); void SetCondition(::Condition* condition);
bool CheckCondition(ConditionContext& context) const; virtual bool CheckCondition(ConditionContext& context) const;
const ::Event* Event() const; const ::Event* Event() const;
::Event* Event(); ::Event* Event();
+7 -2
View File
@@ -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 /*static*/ bool
Events::TriggerDemand(Event* event) Events::TriggerDemand(Event* event)
{ {
if (event == NULL) if (event == NULL || event->Triggered())
return false; return false;
if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
@@ -551,7 +556,7 @@ Events::TriggerDemand(Event* event)
Event* childEvent = container->Events().ItemAt(index); Event* childEvent = container->Events().ItemAt(index);
if (dynamic_cast<DemandEvent*>(childEvent) != NULL) { if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
childEvent->Trigger(); childEvent->Trigger();
return true; break;
} }
if (dynamic_cast<EventContainer*>(childEvent) != NULL) { if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
if (TriggerDemand(childEvent)) if (TriggerDemand(childEvent))
+14
View File
@@ -41,6 +41,10 @@ Job::Job(const Job& other)
fTarget(other.Target()) fTarget(other.Target())
{ {
fCondition = other.fCondition; fCondition = other.fCondition;
// TODO: copy events
//fEvent = other.fEvent;
fEnvironment = other.fEnvironment;
fSourceFiles = other.fSourceFiles;
for (int32 i = 0; i < other.Arguments().CountStrings(); i++) for (int32 i = 0; i < other.Arguments().CountStrings(); i++)
AddArgument(other.Arguments().StringAt(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 status_t
Job::Init(const Finder& finder, std::set<BString>& dependencies) Job::Init(const Finder& finder, std::set<BString>& dependencies)
{ {
+2
View File
@@ -54,6 +54,8 @@ public:
BStringList& Requirements(); BStringList& Requirements();
void AddRequirement(const char* requirement); void AddRequirement(const char* requirement);
virtual bool CheckCondition(ConditionContext& context) const;
status_t Init(const Finder& jobs, status_t Init(const Finder& jobs,
std::set<BString>& dependencies); std::set<BString>& dependencies);
status_t InitCheck() const; status_t InitCheck() const;
+54 -35
View File
@@ -134,10 +134,10 @@ private:
const char* name); const char* name);
void _AddJob(Target* target, bool service, void _AddJob(Target* target, bool service,
BMessage& message); BMessage& message);
void _InitJobs(); void _InitJobs(Target* target);
void _LaunchJobs(Target* target); void _LaunchJobs(Target* target,
void _TriggerJob(Job* job); bool forceNow = false);
void _AddLaunchJob(Job* job); void _LaunchJob(Job* job, bool forceNow = false);
void _AddTarget(Target* target); void _AddTarget(Target* target);
void _SetCondition(BaseJob* job, void _SetCondition(BaseJob* job,
const BMessage& message); const BMessage& message);
@@ -361,7 +361,7 @@ 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);
_InitJobs(); _InitJobs(NULL);
_LaunchJobs(NULL); _LaunchJobs(NULL);
// Launch run targets (ignores events) // Launch run targets (ignores events)
@@ -414,13 +414,13 @@ LaunchDaemon::MessageReceived(BMessage* message)
break; break;
Job* job = FindJob(name); Job* job = FindJob(name);
if (job != NULL && job->EventHasTriggered()) { if (job != NULL) {
_TriggerJob(job); _LaunchJob(job);
break; break;
} }
Target* target = FindTarget(name); Target* target = FindTarget(name);
if (target != NULL && target->EventHasTriggered()) { if (target != NULL) {
_LaunchJobs(target); _LaunchJobs(target);
break; break;
} }
@@ -442,7 +442,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
return; return;
BMessage reply((uint32)B_OK); BMessage reply((uint32)B_OK);
bool triggerJob = true; bool launchJob = true;
Job* job = FindJob(get_leaf(message->GetString("name"))); Job* job = FindJob(get_leaf(message->GetString("name")));
if (job == NULL) { if (job == NULL) {
@@ -454,7 +454,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
} }
reply.what = B_NAME_NOT_FOUND; reply.what = B_NAME_NOT_FOUND;
} else if (!job->IsLaunched()) { } 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 // The job exists, but cannot be started yet, as its
// conditions are not met; don't make it available yet // conditions are not met; don't make it available yet
// TODO: we may not want to initialize jobs with conditions // 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 // The job is not triggered by demand; we cannot start it now
reply.what = B_NO_INIT; reply.what = B_NO_INIT;
} else { } else {
// The job has already been triggered, don't trigger it // The job has already been triggered, don't launch it again
// again launchJob = false;
triggerJob = false;
} }
} }
} }
@@ -490,8 +489,9 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
iterator->second.GetInt32("port", -1)); iterator->second.GetInt32("port", -1));
} }
if (triggerJob) // Launch the job if it hasn't been launched already
_TriggerJob(job); if (launchJob)
_LaunchJob(job);
} }
message->SendReply(&reply); 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 void
LaunchDaemon::_InitJobs() LaunchDaemon::_InitJobs(Target* target)
{ {
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();) { for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();) {
Job* job = iterator->second; Job* job = iterator->second;
JobMap::iterator remove = iterator++; JobMap::iterator remove = iterator++;
if (job->Target() != target)
continue;
status_t status = B_NO_INIT; status_t status = B_NO_INIT;
if (job->IsEnabled()) { if (job->IsEnabled()) {
// Filter out jobs that have a constant and failing condition // 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 /*! 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 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; return;
}
if (target != NULL && !target->HasLaunched()) {
target->SetLaunched(true);
_InitJobs(target);
}
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end(); for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
iterator++) { iterator++) {
Job* job = iterator->second; Job* job = iterator->second;
if (job->Target() == target if (job->Target() == target)
&& (job->Event() == NULL || job->Event()->Triggered())) _LaunchJob(job);
_TriggerJob(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 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; return;
}
int32 count = job->Requirements().CountStrings(); int32 count = job->Requirements().CountStrings();
for (int32 index = 0; index < count; index++) { for (int32 index = 0; index < count; index++) {
Job* requirement = FindJob(job->Requirements().StringAt(index)); Job* requirement = FindJob(job->Requirements().StringAt(index));
if (requirement != NULL) 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) if (job->Target() != NULL)
job->Target()->ResolveSourceFiles(); job->Target()->ResolveSourceFiles();
if (job->Event() != NULL) if (job->Event() != NULL)
job->Event()->ResetTrigger(); job->Event()->ResetTrigger();
if (!job->IsLaunched() && job->CheckCondition(*this)) fJobQueue.AddJob(job);
fJobQueue.AddJob(job);
} }
+9 -1
View File
@@ -9,7 +9,8 @@
Target::Target(const char* name) 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 status_t
Target::Execute() Target::Execute()
{ {
+5
View File
@@ -22,11 +22,16 @@ public:
const BMessage& Data() const const BMessage& Data() const
{ return fData; } { return fData; }
bool HasLaunched() const
{ return fLaunched; }
void SetLaunched(bool launched);
protected: protected:
virtual status_t Execute(); virtual status_t Execute();
private: private:
BMessage fData; BMessage fData;
bool fLaunched;
}; };