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:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user