launch_daemon: Outlined basic event mechanism.
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <Message.h>
|
||||
|
||||
#include "Conditions.h"
|
||||
#include "Events.h"
|
||||
|
||||
|
||||
BaseJob::BaseJob(const char* name)
|
||||
@@ -68,6 +69,35 @@ BaseJob::CheckCondition(ConditionContext& context) const
|
||||
}
|
||||
|
||||
|
||||
const ::Event*
|
||||
BaseJob::Event() const
|
||||
{
|
||||
return fEvent;
|
||||
}
|
||||
|
||||
|
||||
::Event*
|
||||
BaseJob::Event()
|
||||
{
|
||||
return fEvent;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BaseJob::SetEvent(::Event* event)
|
||||
{
|
||||
fEvent = event;
|
||||
event->SetOwner(this);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BaseJob::EventHasTriggered() const
|
||||
{
|
||||
return Event() != NULL && Event()->Triggered();
|
||||
}
|
||||
|
||||
|
||||
const BStringList&
|
||||
BaseJob::Environment() const
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ using namespace BSupportKit;
|
||||
class BMessage;
|
||||
class Condition;
|
||||
class ConditionContext;
|
||||
class Event;
|
||||
|
||||
|
||||
class BaseJob : public BJob {
|
||||
@@ -29,6 +30,11 @@ public:
|
||||
void SetCondition(::Condition* condition);
|
||||
bool CheckCondition(ConditionContext& context) const;
|
||||
|
||||
const ::Event* Event() const;
|
||||
::Event* Event();
|
||||
void SetEvent(::Event* event);
|
||||
bool EventHasTriggered() const;
|
||||
|
||||
const BStringList& Environment() const;
|
||||
BStringList& Environment();
|
||||
const BStringList& EnvironmentSourceFiles() const;
|
||||
@@ -47,6 +53,7 @@ private:
|
||||
|
||||
protected:
|
||||
::Condition* fCondition;
|
||||
::Event* fEvent;
|
||||
BStringList fEnvironment;
|
||||
BStringList fSourceFiles;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright 2015, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Events.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <ObjectList.h>
|
||||
#include <Message.h>
|
||||
#include <Path.h>
|
||||
#include <StringList.h>
|
||||
|
||||
#include "BaseJob.h"
|
||||
#include "LaunchDaemon.h"
|
||||
#include "Utility.h"
|
||||
|
||||
|
||||
class EventContainer : public Event {
|
||||
protected:
|
||||
EventContainer(Event* parent,
|
||||
const BMessenger* target,
|
||||
const BMessage& args);
|
||||
EventContainer(BaseJob* owner,
|
||||
const BMessenger& target);
|
||||
|
||||
public:
|
||||
void AddEvent(Event* event);
|
||||
BObjectList<Event>& Events();
|
||||
|
||||
const BMessenger& Target() const;
|
||||
|
||||
virtual status_t Register(EventRegistrator& registrator) const;
|
||||
virtual void Unregister(EventRegistrator& registrator) const;
|
||||
|
||||
virtual void Trigger();
|
||||
|
||||
virtual BaseJob* Owner() const;
|
||||
virtual void SetOwner(BaseJob* owner);
|
||||
|
||||
protected:
|
||||
void ToString(BString& string) const;
|
||||
|
||||
protected:
|
||||
BaseJob* fOwner;
|
||||
BMessenger fTarget;
|
||||
BObjectList<Event> fEvents;
|
||||
};
|
||||
|
||||
|
||||
class OrEvent : public EventContainer {
|
||||
public:
|
||||
OrEvent(Event* parent, const BMessenger* target,
|
||||
const BMessage& args);
|
||||
OrEvent(BaseJob* owner,
|
||||
const BMessenger& target);
|
||||
|
||||
virtual BString ToString() const;
|
||||
};
|
||||
|
||||
|
||||
class DemandEvent : public Event {
|
||||
public:
|
||||
DemandEvent(Event* parent);
|
||||
|
||||
virtual status_t Register(EventRegistrator& registrator) const;
|
||||
virtual void Unregister(EventRegistrator& registrator) const;
|
||||
|
||||
virtual BString ToString() const;
|
||||
};
|
||||
|
||||
|
||||
class FileCreatedEvent : public Event {
|
||||
public:
|
||||
FileCreatedEvent(Event* parent,
|
||||
const BMessage& args);
|
||||
|
||||
virtual status_t Register(EventRegistrator& registrator) const;
|
||||
virtual void Unregister(EventRegistrator& registrator) const;
|
||||
|
||||
virtual BString ToString() const;
|
||||
|
||||
private:
|
||||
BPath fPath;
|
||||
};
|
||||
|
||||
|
||||
static Event*
|
||||
create_event(Event* parent, const char* name, const BMessenger* target,
|
||||
const BMessage& args)
|
||||
{
|
||||
if (strcmp(name, "or") == 0)
|
||||
return new OrEvent(parent, target, args);
|
||||
|
||||
if (strcmp(name, "demand") == 0)
|
||||
return new DemandEvent(parent);
|
||||
if (strcmp(name, "file_created") == 0)
|
||||
return new FileCreatedEvent(parent, args);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Event::Event(Event* parent)
|
||||
:
|
||||
fParent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Event::~Event()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Event::Triggered() const
|
||||
{
|
||||
return fTriggered;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Event::Trigger()
|
||||
{
|
||||
fTriggered = true;
|
||||
if (fParent != NULL)
|
||||
fParent->Trigger();
|
||||
}
|
||||
|
||||
|
||||
BaseJob*
|
||||
Event::Owner() const
|
||||
{
|
||||
if (fParent != NULL)
|
||||
return fParent->Owner();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Event::SetOwner(BaseJob* owner)
|
||||
{
|
||||
if (fParent != NULL)
|
||||
fParent->SetOwner(owner);
|
||||
}
|
||||
|
||||
|
||||
Event*
|
||||
Event::Parent() const
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
EventContainer::EventContainer(Event* parent, const BMessenger* target,
|
||||
const BMessage& args)
|
||||
:
|
||||
Event(parent),
|
||||
fEvents(5, true)
|
||||
{
|
||||
if (target != NULL)
|
||||
fTarget = *target;
|
||||
|
||||
char* name;
|
||||
type_code type;
|
||||
int32 count;
|
||||
for (int32 index = 0; args.GetInfo(B_MESSAGE_TYPE, index, &name, &type,
|
||||
&count) == B_OK; index++) {
|
||||
BMessage message;
|
||||
for (int32 messageIndex = 0; args.FindMessage(name, messageIndex,
|
||||
&message) == B_OK; messageIndex++) {
|
||||
AddEvent(create_event(this, name, target, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EventContainer::EventContainer(BaseJob* owner, const BMessenger& target)
|
||||
:
|
||||
Event(NULL),
|
||||
fOwner(owner),
|
||||
fTarget(target),
|
||||
fEvents(5, true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventContainer::AddEvent(Event* event)
|
||||
{
|
||||
if (event != NULL)
|
||||
fEvents.AddItem(event);
|
||||
}
|
||||
|
||||
|
||||
BObjectList<Event>&
|
||||
EventContainer::Events()
|
||||
{
|
||||
return fEvents;
|
||||
}
|
||||
|
||||
|
||||
const BMessenger&
|
||||
EventContainer::Target() const
|
||||
{
|
||||
return fTarget;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
EventContainer::Register(EventRegistrator& registrator) const
|
||||
{
|
||||
int32 count = fEvents.CountItems();
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
Event* event = fEvents.ItemAt(index);
|
||||
status_t status = event->Register(registrator);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventContainer::Unregister(EventRegistrator& registrator) const
|
||||
{
|
||||
int32 count = fEvents.CountItems();
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
Event* event = fEvents.ItemAt(index);
|
||||
event->Unregister(registrator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventContainer::Trigger()
|
||||
{
|
||||
Event::Trigger();
|
||||
|
||||
if (Parent() == NULL && Owner() != NULL) {
|
||||
BMessage message(kMsgEventTriggered);
|
||||
message.AddString("owner", Owner()->Name());
|
||||
fTarget.SendMessage(&message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BaseJob*
|
||||
EventContainer::Owner() const
|
||||
{
|
||||
return fOwner;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventContainer::SetOwner(BaseJob* owner)
|
||||
{
|
||||
Event::SetOwner(owner);
|
||||
fOwner = owner;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventContainer::ToString(BString& string) const
|
||||
{
|
||||
string += "[";
|
||||
|
||||
for (int32 index = 0; index < fEvents.CountItems(); index++) {
|
||||
if (index != 0)
|
||||
string += ", ";
|
||||
string += fEvents.ItemAt(index)->ToString();
|
||||
}
|
||||
string += "]";
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - or
|
||||
|
||||
|
||||
OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args)
|
||||
:
|
||||
EventContainer(parent, target, args)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
OrEvent::OrEvent(BaseJob* owner, const BMessenger& target)
|
||||
:
|
||||
EventContainer(owner, target)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
OrEvent::ToString() const
|
||||
{
|
||||
BString string = "or ";
|
||||
EventContainer::ToString(string);
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - demand
|
||||
|
||||
|
||||
DemandEvent::DemandEvent(Event* parent)
|
||||
:
|
||||
Event(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DemandEvent::Register(EventRegistrator& registrator) const
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DemandEvent::Unregister(EventRegistrator& registrator) const
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
DemandEvent::ToString() const
|
||||
{
|
||||
return "event";
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - file_created
|
||||
|
||||
|
||||
FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args)
|
||||
:
|
||||
Event(parent)
|
||||
{
|
||||
fPath.SetTo(args.GetString("args", NULL));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileCreatedEvent::Register(EventRegistrator& registrator) const
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileCreatedEvent::Unregister(EventRegistrator& registrator) const
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
FileCreatedEvent::ToString() const
|
||||
{
|
||||
BString string = "file_created ";
|
||||
string << fPath.Path();
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
/*static*/ Event*
|
||||
Events::FromMessage(const BMessenger& target, const BMessage& message)
|
||||
{
|
||||
return create_event(NULL, "or", &target, message);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ Event*
|
||||
Events::AddOnDemand(Event* event)
|
||||
{
|
||||
OrEvent* or = dynamic_cast<OrEvent*>(event);
|
||||
if (or == NULL) {
|
||||
EventContainer* container = dynamic_cast<EventContainer*>(event);
|
||||
if (container == NULL)
|
||||
return NULL;
|
||||
|
||||
or = new OrEvent(container->Owner(), container->Target());
|
||||
}
|
||||
if (or != event && event != NULL)
|
||||
or->AddEvent(event);
|
||||
|
||||
or->AddEvent(new DemandEvent(or));
|
||||
return or;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
Events::TriggerDemand(Event* event)
|
||||
{
|
||||
if (event == NULL)
|
||||
return false;
|
||||
|
||||
if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
|
||||
for (int32 index = 0; index < container->Events().CountItems();
|
||||
index++) {
|
||||
Event* event = container->Events().ItemAt(index);
|
||||
if (dynamic_cast<DemandEvent*>(event) != NULL) {
|
||||
event->Trigger();
|
||||
return true;
|
||||
}
|
||||
if (dynamic_cast<EventContainer*>(event) != NULL) {
|
||||
if (TriggerDemand(event))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2015, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef EVENTS_H
|
||||
#define EVENTS_H
|
||||
|
||||
|
||||
#include <Messenger.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class BaseJob;
|
||||
class Event;
|
||||
|
||||
|
||||
class EventRegistrator {
|
||||
public:
|
||||
virtual status_t RegisterEvent(Event* event) = 0;
|
||||
virtual void UnregisterEvent(Event* event) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Event {
|
||||
public:
|
||||
Event(Event* parent);
|
||||
virtual ~Event();
|
||||
|
||||
virtual status_t Register(
|
||||
EventRegistrator& registrator) const = 0;
|
||||
virtual void Unregister(
|
||||
EventRegistrator& registrator) const = 0;
|
||||
|
||||
bool Triggered() const;
|
||||
virtual void Trigger();
|
||||
|
||||
virtual BaseJob* Owner() const;
|
||||
virtual void SetOwner(BaseJob* owner);
|
||||
|
||||
Event* Parent() const;
|
||||
|
||||
virtual BString ToString() const = 0;
|
||||
|
||||
private:
|
||||
Event* fParent;
|
||||
bool fTriggered;
|
||||
};
|
||||
|
||||
|
||||
class Events {
|
||||
public:
|
||||
static Event* FromMessage(const BMessenger& target,
|
||||
const BMessage& message);
|
||||
static Event* AddOnDemand(Event* event);
|
||||
static bool TriggerDemand(Event* event);
|
||||
};
|
||||
|
||||
|
||||
#endif // EVENTS_H
|
||||
@@ -11,6 +11,7 @@ Server launch_daemon
|
||||
|
||||
BaseJob.cpp
|
||||
Conditions.cpp
|
||||
Events.cpp
|
||||
Job.cpp
|
||||
SettingsParser.cpp
|
||||
Target.cpp
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "LaunchDaemon.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
@@ -31,6 +33,7 @@
|
||||
#include "multiuser_utils.h"
|
||||
|
||||
#include "Conditions.h"
|
||||
#include "Events.h"
|
||||
#include "InitRealTimeClockJob.h"
|
||||
#include "InitSharedMemoryDirectoryJob.h"
|
||||
#include "InitTemporaryDirectoryJob.h"
|
||||
@@ -102,10 +105,13 @@ private:
|
||||
BMessage& message);
|
||||
void _InitJobs();
|
||||
void _LaunchJobs(Target* target);
|
||||
void _TriggerJob(Job* job);
|
||||
void _AddLaunchJob(Job* job);
|
||||
void _AddTarget(Target* target);
|
||||
void _SetCondition(BaseJob* job,
|
||||
const BMessage& message);
|
||||
void _SetEvent(BaseJob* job,
|
||||
const BMessage& message);
|
||||
void _SetEnvironment(BaseJob* job,
|
||||
const BMessage& message);
|
||||
|
||||
@@ -261,7 +267,7 @@ LaunchDaemon::ReadyToRun()
|
||||
_InitJobs();
|
||||
_LaunchJobs(NULL);
|
||||
|
||||
// Launch run targets
|
||||
// Launch run targets (ignores events)
|
||||
for (int32 index = 0; index < fRunTargets.CountStrings(); index++) {
|
||||
Target* target = FindTarget(fRunTargets.StringAt(index));
|
||||
if (target != NULL)
|
||||
@@ -314,7 +320,7 @@ LaunchDaemon::MessageReceived(BMessage* message)
|
||||
iterator->second.GetInt32("port", -1));
|
||||
}
|
||||
|
||||
_AddLaunchJob(job);
|
||||
_TriggerJob(job);
|
||||
}
|
||||
message->SendReply(&reply);
|
||||
break;
|
||||
@@ -419,6 +425,28 @@ LaunchDaemon::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgEventTriggered:
|
||||
{
|
||||
// An internal event has been triggered.
|
||||
// Check if its job can be launched now.
|
||||
const char* name = message->GetString("owner");
|
||||
if (name == NULL)
|
||||
break;
|
||||
|
||||
Job* job = FindJob(name);
|
||||
if (job != NULL && job->EventHasTriggered()) {
|
||||
_AddLaunchJob(job);
|
||||
break;
|
||||
}
|
||||
|
||||
Target* target = FindTarget(name);
|
||||
if (target != NULL && target->EventHasTriggered()) {
|
||||
_LaunchJobs(target);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BServer::MessageReceived(message);
|
||||
break;
|
||||
@@ -542,6 +570,7 @@ LaunchDaemon::_AddTargets(BMessage& message)
|
||||
}
|
||||
|
||||
_SetCondition(target, targetMessage);
|
||||
_SetEvent(target, targetMessage);
|
||||
_SetEnvironment(target, targetMessage);
|
||||
_AddJobs(target, targetMessage);
|
||||
}
|
||||
@@ -620,6 +649,7 @@ LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message)
|
||||
job->SetCreateDefaultPort(!message.GetBool("legacy", !service));
|
||||
|
||||
_SetCondition(job, message);
|
||||
_SetEvent(job, message);
|
||||
_SetEnvironment(job, message);
|
||||
|
||||
BMessage portMessage;
|
||||
@@ -683,6 +713,9 @@ LaunchDaemon::_InitJobs()
|
||||
}
|
||||
|
||||
|
||||
/*! Adds all jobs for the specified target (may be \c NULL) to the launch
|
||||
queue, except those that are triggered by events.
|
||||
*/
|
||||
void
|
||||
LaunchDaemon::_LaunchJobs(Target* target)
|
||||
{
|
||||
@@ -692,12 +725,30 @@ LaunchDaemon::_LaunchJobs(Target* target)
|
||||
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
|
||||
iterator++) {
|
||||
Job* job = iterator->second;
|
||||
if (job->Target() == target)
|
||||
_AddLaunchJob(job);
|
||||
if (job->Target() == target && job->Event() == NULL)
|
||||
_TriggerJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_TriggerJob(Job* job)
|
||||
{
|
||||
if (job == NULL)
|
||||
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);
|
||||
}
|
||||
|
||||
if (!Events::TriggerDemand(job->Event()))
|
||||
_AddLaunchJob(job);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_AddLaunchJob(Job* job)
|
||||
{
|
||||
@@ -738,6 +789,28 @@ LaunchDaemon::_SetCondition(BaseJob* job, const BMessage& message)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_SetEvent(BaseJob* job, const BMessage& message)
|
||||
{
|
||||
Event* event = job->Event();
|
||||
bool updated = false;
|
||||
|
||||
BMessage events;
|
||||
if (message.FindMessage("on", &events) == B_OK) {
|
||||
event = Events::FromMessage(this, events);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (message.GetBool("on_demand")) {
|
||||
event = Events::AddOnDemand(event);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
job->SetEvent(event);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_SetEnvironment(BaseJob* job, const BMessage& message)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LAUNCH_DAEMON_H
|
||||
#define LAUNCH_DAEMON_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
static const uint32 kMsgEventTriggered = 'ldet';
|
||||
|
||||
|
||||
#endif // LAUNCH_DAEMON_H
|
||||
@@ -156,6 +156,7 @@ const static settings_template kJobTemplate[] = {
|
||||
{B_MESSAGE_TYPE, "on", kEventTemplate},
|
||||
{B_MESSAGE_TYPE, "if", kConditionTemplate},
|
||||
{B_BOOL_TYPE, "no_safemode", NULL},
|
||||
{B_BOOL_TYPE, "on_demand", NULL},
|
||||
{B_MESSAGE_TYPE, "env", kEnvTemplate},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user