launch_daemon: Outlined basic event mechanism.

This commit is contained in:
Axel Dörfler
2015-07-22 20:44:53 +02:00
parent 1ec3f11d97
commit 5b6c827e82
8 changed files with 618 additions and 4 deletions
+30
View File
@@ -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
{
+7
View File
@@ -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;
};
+428
View File
@@ -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;
}
+59
View File
@@ -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
+1
View File
@@ -11,6 +11,7 @@ Server launch_daemon
BaseJob.cpp
Conditions.cpp
Events.cpp
Job.cpp
SettingsParser.cpp
Target.cpp
+77 -4
View File
@@ -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)
{
+15
View File
@@ -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
+1
View File
@@ -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}
};