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
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;
::Condition* Condition();
void SetCondition(::Condition* condition);
bool CheckCondition(ConditionContext& context) const;
virtual bool CheckCondition(ConditionContext& context) const;
const ::Event* Event() const;
::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
Events::TriggerDemand(Event* event)
{
if (event == NULL)
if (event == NULL || event->Triggered())
return false;
if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
@@ -551,7 +556,7 @@ Events::TriggerDemand(Event* event)
Event* childEvent = container->Events().ItemAt(index);
if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
childEvent->Trigger();
return true;
break;
}
if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
if (TriggerDemand(childEvent))
+14
View File
@@ -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<BString>& dependencies)
{
+2
View File
@@ -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<BString>& dependencies);
status_t InitCheck() const;
+54 -35
View File
@@ -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);
}
+9 -1
View File
@@ -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()
{
+5
View File
@@ -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;
};