From 7cd19b7e5c0e66b06a3064275dd7519e50a7f89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 17 Oct 2015 14:07:53 +0200 Subject: [PATCH] launch_daemon: Implemented sticky events, and registration. * Sticky events are events that keep their signal raised, ie. even if a job is initialized afterwards, it will still be triggered. * Consolidated naming for external events. * Events are now registered once they are actually being used. This allows them to allocate the resources they need to do their thing. --- docs/user/app/LaunchRoster.dox | 5 ++ headers/private/app/LaunchRoster.h | 11 +++- src/kits/app/LaunchRoster.cpp | 9 ++- src/servers/launch/Events.cpp | 96 ++++++++++++++++++++--------- src/servers/launch/Events.h | 21 ++++--- src/servers/launch/Job.cpp | 23 ++++++- src/servers/launch/Job.h | 3 + src/servers/launch/LaunchDaemon.cpp | 66 +++++++++++++++----- src/servers/mount/AutoMounter.cpp | 2 +- 9 files changed, 178 insertions(+), 58 deletions(-) diff --git a/docs/user/app/LaunchRoster.dox b/docs/user/app/LaunchRoster.dox index 0fe375e424..0eaf43864f 100644 --- a/docs/user/app/LaunchRoster.dox +++ b/docs/user/app/LaunchRoster.dox @@ -211,8 +211,13 @@ on { The latter form can be used to solve ambiguous event definitions. + By specifying the \c B_STICKY_EVENT flag, you can mark the event as being + a permanent change. Once triggered, such an event will stay triggered, ie. + even new targets or jobs will consider it triggered. + \param source The messenger the event is coming from. \param name The name of the event. + \param flags Flags for the event as described. \return B_OK if the event could be registered, otherwise an error code. \since Haiku R1 diff --git a/headers/private/app/LaunchRoster.h b/headers/private/app/LaunchRoster.h index 827d667ee5..32e05e89e3 100644 --- a/headers/private/app/LaunchRoster.h +++ b/headers/private/app/LaunchRoster.h @@ -9,6 +9,12 @@ #include +// Flags for RegisterEvent() +enum { + B_STICKY_EVENT = 0x01 +}; + + class BLaunchRoster { public: BLaunchRoster(); @@ -31,7 +37,7 @@ public: status_t StartSession(const char* login); status_t RegisterEvent(const BMessenger& source, - const char* name); + const char* name, uint32 flags); status_t UnregisterEvent(const BMessenger& source, const char* name); status_t NotifyEvent(const BMessenger& source, @@ -44,7 +50,8 @@ private: void _InitMessenger(); status_t _UpdateEvent(uint32 what, - const BMessenger& source, const char* name); + const BMessenger& source, const char* name, + uint32 flags = 0); private: BMessenger fMessenger; diff --git a/src/kits/app/LaunchRoster.cpp b/src/kits/app/LaunchRoster.cpp index 7770534ace..dee7401322 100644 --- a/src/kits/app/LaunchRoster.cpp +++ b/src/kits/app/LaunchRoster.cpp @@ -206,9 +206,10 @@ BLaunchRoster::StartSession(const char* login) status_t -BLaunchRoster::RegisterEvent(const BMessenger& source, const char* name) +BLaunchRoster::RegisterEvent(const BMessenger& source, const char* name, + uint32 flags) { - return _UpdateEvent(B_REGISTER_LAUNCH_EVENT, source, name); + return _UpdateEvent(B_REGISTER_LAUNCH_EVENT, source, name, flags); } @@ -241,7 +242,7 @@ BLaunchRoster::_InitMessenger() status_t BLaunchRoster::_UpdateEvent(uint32 what, const BMessenger& source, - const char* name) + const char* name, uint32 flags) { if (be_app == NULL || name == NULL || name[0] == '\0') return B_BAD_VALUE; @@ -254,6 +255,8 @@ BLaunchRoster::_UpdateEvent(uint32 what, const BMessenger& source, status = request.AddString("owner", be_app->Signature()); if (status == B_OK) status = request.AddString("name", name); + if (status == B_OK && flags != 0) + status = request.AddUInt32("flags", flags); if (status != B_OK) return status; diff --git a/src/servers/launch/Events.cpp b/src/servers/launch/Events.cpp index 29b6edb169..7326fd68fe 100644 --- a/src/servers/launch/Events.cpp +++ b/src/servers/launch/Events.cpp @@ -9,8 +9,9 @@ #include #include -#include +#include #include +#include #include #include @@ -33,8 +34,8 @@ public: const BMessenger& Target() const; - virtual status_t Register(EventRegistrator& registrator) const; - virtual void Unregister(EventRegistrator& registrator) const; + virtual status_t Register(EventRegistrator& registrator); + virtual void Unregister(EventRegistrator& registrator); virtual void Trigger(); @@ -48,6 +49,7 @@ protected: BaseJob* fOwner; BMessenger fTarget; BObjectList fEvents; + bool fRegistered; }; @@ -58,6 +60,8 @@ public: OrEvent(BaseJob* owner, const BMessenger& target); + virtual void ResetTrigger(); + virtual BString ToString() const; }; @@ -66,8 +70,8 @@ class DemandEvent : public Event { public: DemandEvent(Event* parent); - virtual status_t Register(EventRegistrator& registrator) const; - virtual void Unregister(EventRegistrator& registrator) const; + virtual status_t Register(EventRegistrator& registrator); + virtual void Unregister(EventRegistrator& registrator); virtual BString ToString() const; }; @@ -79,16 +83,19 @@ public: const BMessage& args); const BString& Name() const; - bool Resolve(); + bool Resolve(uint32 flags); - virtual status_t Register(EventRegistrator& registrator) const; - virtual void Unregister(EventRegistrator& registrator) const; + virtual void ResetTrigger(); + + virtual status_t Register(EventRegistrator& registrator); + virtual void Unregister(EventRegistrator& registrator); virtual BString ToString() const; private: BString fName; BStringList fArguments; + uint32 fFlags; bool fResolved; }; @@ -98,8 +105,8 @@ public: FileCreatedEvent(Event* parent, const BMessage& args); - virtual status_t Register(EventRegistrator& registrator) const; - virtual void Unregister(EventRegistrator& registrator) const; + virtual status_t Register(EventRegistrator& registrator); + virtual void Unregister(EventRegistrator& registrator); virtual BString ToString() const; @@ -198,7 +205,8 @@ EventContainer::EventContainer(Event* parent, const BMessenger* target, const BMessage& args) : Event(parent), - fEvents(5, true) + fEvents(5, true), + fRegistered(false) { if (target != NULL) fTarget = *target; @@ -222,7 +230,8 @@ EventContainer::EventContainer(BaseJob* owner, const BMessenger& target) Event(NULL), fOwner(owner), fTarget(target), - fEvents(5, true) + fEvents(5, true), + fRegistered(false) { } @@ -250,8 +259,11 @@ EventContainer::Target() const status_t -EventContainer::Register(EventRegistrator& registrator) const +EventContainer::Register(EventRegistrator& registrator) { + if (fRegistered) + return B_OK; + int32 count = fEvents.CountItems(); for (int32 index = 0; index < count; index++) { Event* event = fEvents.ItemAt(index); @@ -260,12 +272,13 @@ EventContainer::Register(EventRegistrator& registrator) const return status; } + fRegistered = true; return B_OK; } void -EventContainer::Unregister(EventRegistrator& registrator) const +EventContainer::Unregister(EventRegistrator& registrator) { int32 count = fEvents.CountItems(); for (int32 index = 0; index < count; index++) { @@ -334,6 +347,20 @@ OrEvent::OrEvent(BaseJob* owner, const BMessenger& target) } +void +OrEvent::ResetTrigger() +{ + fTriggered = false; + + int32 count = fEvents.CountItems(); + for (int32 index = 0; index < count; index++) { + Event* event = fEvents.ItemAt(index); + event->ResetTrigger(); + fTriggered |= event->Triggered(); + } +} + + BString OrEvent::ToString() const { @@ -354,14 +381,14 @@ DemandEvent::DemandEvent(Event* parent) status_t -DemandEvent::Register(EventRegistrator& registrator) const +DemandEvent::Register(EventRegistrator& registrator) { return B_OK; } void -DemandEvent::Unregister(EventRegistrator& registrator) const +DemandEvent::Unregister(EventRegistrator& registrator) { } @@ -381,6 +408,7 @@ ExternalEvent::ExternalEvent(Event* parent, const char* name, : Event(parent), fName(name), + fFlags(0), fResolved(false) { const char* argument; @@ -399,26 +427,38 @@ ExternalEvent::Name() const bool -ExternalEvent::Resolve() +ExternalEvent::Resolve(uint32 flags) { if (fResolved) return false; fResolved = true; + fFlags = flags; return true; } -status_t -ExternalEvent::Register(EventRegistrator& registrator) const +void +ExternalEvent::ResetTrigger() { - return B_OK; + if ((fFlags & B_STICKY_EVENT) != 0) + return; + + Event::ResetTrigger(); +} + + +status_t +ExternalEvent::Register(EventRegistrator& registrator) +{ + return registrator.RegisterExternalEvent(this, Name().String(), fArguments); } void -ExternalEvent::Unregister(EventRegistrator& registrator) const +ExternalEvent::Unregister(EventRegistrator& registrator) { + registrator.UnregisterExternalEvent(this, Name().String()); } @@ -441,7 +481,7 @@ FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args) status_t -FileCreatedEvent::Register(EventRegistrator& registrator) const +FileCreatedEvent::Register(EventRegistrator& registrator) { // TODO: implement! return B_ERROR; @@ -449,7 +489,7 @@ FileCreatedEvent::Register(EventRegistrator& registrator) const void -FileCreatedEvent::Unregister(EventRegistrator& registrator) const +FileCreatedEvent::Unregister(EventRegistrator& registrator) { } @@ -493,7 +533,7 @@ Events::AddOnDemand(const BMessenger& target, Event* event) /*static*/ bool -Events::ResolveRegisteredEvent(Event* event, const char* name) +Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags) { if (event == NULL) return false; @@ -503,10 +543,10 @@ Events::ResolveRegisteredEvent(Event* event, const char* name) index++) { Event* event = container->Events().ItemAt(index); if (ExternalEvent* external = dynamic_cast(event)) { - if (external->Name() == name && external->Resolve()) + if (external->Name() == name && external->Resolve(flags)) return true; } else if (dynamic_cast(event) != NULL) { - if (ResolveRegisteredEvent(event, name)) + if (ResolveExternalEvent(event, name, flags)) return true; } } @@ -516,7 +556,7 @@ Events::ResolveRegisteredEvent(Event* event, const char* name) /*static*/ void -Events::TriggerRegisteredEvent(Event* event, const char* name) +Events::TriggerExternalEvent(Event* event, const char* name) { if (event == NULL) return; @@ -531,7 +571,7 @@ Events::TriggerRegisteredEvent(Event* event, const char* name) return; } } else if (dynamic_cast(event) != NULL) { - TriggerRegisteredEvent(event, name); + TriggerExternalEvent(event, name); } } } diff --git a/src/servers/launch/Events.h b/src/servers/launch/Events.h index a41707bab4..d827182a00 100644 --- a/src/servers/launch/Events.h +++ b/src/servers/launch/Events.h @@ -16,8 +16,11 @@ class Event; class EventRegistrator { public: - virtual status_t RegisterEvent(Event* event) = 0; - virtual void UnregisterEvent(Event* event) = 0; + virtual status_t RegisterExternalEvent(Event* event, + const char* name, + const BStringList& arguments) = 0; + virtual void UnregisterExternalEvent(Event* event, + const char* name) = 0; }; @@ -27,13 +30,13 @@ public: virtual ~Event(); virtual status_t Register( - EventRegistrator& registrator) const = 0; + EventRegistrator& registrator) = 0; virtual void Unregister( - EventRegistrator& registrator) const = 0; + EventRegistrator& registrator) = 0; bool Triggered() const; virtual void Trigger(); - void ResetTrigger(); + virtual void ResetTrigger(); virtual BaseJob* Owner() const; virtual void SetOwner(BaseJob* owner); @@ -42,7 +45,7 @@ public: virtual BString ToString() const = 0; -private: +protected: Event* fParent; bool fTriggered; }; @@ -53,9 +56,9 @@ public: static Event* FromMessage(const BMessenger& target, const BMessage& message); static Event* AddOnDemand(const BMessenger& target, Event* event); - static bool ResolveRegisteredEvent(Event* event, - const char* name); - static void TriggerRegisteredEvent(Event* event, + static bool ResolveExternalEvent(Event* event, + const char* name, uint32 flags); + static void TriggerExternalEvent(Event* event, const char* name); static bool TriggerDemand(Event* event); }; diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp index 13ccd9cec1..a7b28a328d 100644 --- a/src/servers/launch/Job.cpp +++ b/src/servers/launch/Job.cpp @@ -341,6 +341,14 @@ Job::IsLaunched() const } +bool +Job::IsRunning() const +{ + // TODO: monitor team status; should jobs be allowed to run multiple times? + return State() == B_JOB_STATE_SUCCEEDED && IsLaunched() && IsService(); +} + + status_t Job::HandleGetLaunchData(BMessage* message) { @@ -352,10 +360,23 @@ Job::HandleGetLaunchData(BMessage* message) } +status_t +Job::Run() +{ + status_t status = BJob::Run(); + + // TODO: monitor team, don't just do this + if (!IsService()) + SetState(B_JOB_STATE_WAITING_TO_RUN); + + return status; +} + + status_t Job::Execute() { - if (!IsLaunched()) + if (!IsLaunched() || !IsService()) return Launch(); return B_OK; diff --git a/src/servers/launch/Job.h b/src/servers/launch/Job.h index 137491db49..7a6f95a80b 100644 --- a/src/servers/launch/Job.h +++ b/src/servers/launch/Job.h @@ -71,9 +71,12 @@ public: status_t Launch(); bool IsLaunched() const; + bool IsRunning() const; status_t HandleGetLaunchData(BMessage* message); + virtual status_t Run(); + protected: virtual status_t Execute(); diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 958c9b2e39..a1b9d2a227 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -85,10 +85,12 @@ class ExternalEventSource { public: ExternalEventSource(BMessenger& source, const char* ownerName, - const char* name); + const char* name, uint32 flags); ~ExternalEventSource(); const char* Name() const; + uint32 Flags() const + { return fFlags; } int32 CountListeners() const; BaseJob* ListenerAt(int32 index) const; @@ -98,6 +100,7 @@ public: private: BString fName; + uint32 fFlags; BObjectList fListeners; }; @@ -108,7 +111,8 @@ typedef std::map TargetMap; typedef std::map EventMap; -class LaunchDaemon : public BServer, public Finder, public ConditionContext { +class LaunchDaemon : public BServer, public Finder, public ConditionContext, + public EventRegistrator { public: LaunchDaemon(bool userMode, const EventMap& events, status_t& error); @@ -118,9 +122,17 @@ public: virtual Target* FindTarget(const char* name) const; Session* FindSession(uid_t user) const; + // ConditionContext virtual bool IsSafeMode() const; virtual bool BootVolumeIsReadOnly() const; + // EventRegistrator + virtual status_t RegisterExternalEvent(Event* event, + const char* name, + const BStringList& arguments); + virtual void UnregisterExternalEvent(Event* event, + const char* name); + virtual void ReadyToRun(); virtual void MessageReceived(BMessage* message); @@ -218,9 +230,10 @@ Session::Session(uid_t user, const BMessenger& daemon) ExternalEventSource::ExternalEventSource(BMessenger& source, - const char* ownerName, const char* name) + const char* ownerName, const char* name, uint32 flags) : fName(name), + fFlags(flags), fListeners(5, true) { } @@ -352,6 +365,22 @@ LaunchDaemon::BootVolumeIsReadOnly() const } +status_t +LaunchDaemon::RegisterExternalEvent(Event* event, const char* name, + const BStringList& arguments) +{ + // TODO: register actual event with event source + return B_OK; +} + + +void +LaunchDaemon::UnregisterExternalEvent(Event* event, const char* name) +{ + // TODO! +} + + void LaunchDaemon::ReadyToRun() { @@ -482,7 +511,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message) return; } reply.what = B_NAME_NOT_FOUND; - } else if (!job->IsLaunched()) { + } else if (job->IsService() && !job->IsLaunched()) { 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 @@ -638,6 +667,7 @@ LaunchDaemon::_HandleRegisterLaunchEvent(BMessage* message) const char* name = message->GetString("name"); const char* ownerName = message->GetString("owner"); + uint32 flags = message->GetUInt32("flags", 0); BMessenger source; if (name != NULL && ownerName != NULL && message->FindMessenger("source", &source) == B_OK) { @@ -645,7 +675,7 @@ LaunchDaemon::_HandleRegisterLaunchEvent(BMessage* message) ownerName = get_leaf(ownerName); ExternalEventSource* event = new (std::nothrow) - ExternalEventSource(source, ownerName, name); + ExternalEventSource(source, ownerName, name, flags); if (event != NULL) { // Use short name, and fully qualified name BString eventName = name; @@ -723,7 +753,7 @@ LaunchDaemon::_HandleNotifyLaunchEvent(BMessage* message) int32 count = event->CountListeners(); for (int32 index = 0; index < count; index++) { BaseJob* listener = event->ListenerAt(index); - Events::TriggerRegisteredEvent(listener->Event(), name); + Events::TriggerExternalEvent(listener->Event(), name); } } } @@ -851,6 +881,9 @@ LaunchDaemon::_AddTargets(BMessage& message) _SetEvent(target, targetMessage); _SetEnvironment(target, targetMessage); _AddJobs(target, targetMessage); + + if (target->Event() != NULL) + target->Event()->Register(*this); } } @@ -980,6 +1013,8 @@ LaunchDaemon::_InitJobs(Target* target) || job->Condition()->Test(*this)) { std::set dependencies; status = job->Init(*this, dependencies); + if (status == B_OK && job->Event() != NULL) + status = job->Event()->Register(*this); } } @@ -1030,18 +1065,20 @@ LaunchDaemon::_LaunchJobs(Target* target, bool forceNow) /*! 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, + Unless \c FORCE_NOW is set, the target is only launched if its events, if any, have been triggered already. - Calling this method will trigger a demand event. + Calling this method will trigger a demand event if \c TRIGGER_DEMAND has + been set. */ void LaunchDaemon::_LaunchJob(Job* job, uint32 options) { - if (job == NULL || job->IsLaunched() || ((options & FORCE_NOW) == 0 - && (!job->EventHasTriggered() || !job->CheckCondition(*this) - || ((options & TRIGGER_DEMAND) != 0 - && Events::TriggerDemand(job->Event()))))) { + if (job == NULL || (job->IsService() && job->IsLaunched()) + || ((options & FORCE_NOW) == 0 + && (!job->EventHasTriggered() || !job->CheckCondition(*this) + || ((options & TRIGGER_DEMAND) != 0 + && Events::TriggerDemand(job->Event()))))) { return; } @@ -1160,7 +1197,7 @@ LaunchDaemon::_ResolveExternalEvents(ExternalEventSource* event, for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end(); iterator++) { Job* job = iterator->second; - if (Events::ResolveRegisteredEvent(job->Event(), name)) + if (Events::ResolveExternalEvent(job->Event(), name, event->Flags())) event->AddListener(job); } } @@ -1175,7 +1212,8 @@ LaunchDaemon::_ResolveExternalEvents(BaseJob* job) for (EventMap::iterator iterator = fEvents.begin(); iterator != fEvents.end(); iterator++) { ExternalEventSource* event = iterator->second; - if (Events::ResolveRegisteredEvent(job->Event(), event->Name())) + if (Events::ResolveExternalEvent(job->Event(), event->Name(), + event->Flags())) event->AddListener(job); } } diff --git a/src/servers/mount/AutoMounter.cpp b/src/servers/mount/AutoMounter.cpp index dca79297d1..4c63058828 100644 --- a/src/servers/mount/AutoMounter.cpp +++ b/src/servers/mount/AutoMounter.cpp @@ -81,7 +81,7 @@ AutoMounter::AutoMounter() BDiskDeviceRoster().StartWatching(this, B_DEVICE_REQUEST_DEVICE | B_DEVICE_REQUEST_DEVICE_LIST); - BLaunchRoster().RegisterEvent(this, kInitialMountEvent); + BLaunchRoster().RegisterEvent(this, kInitialMountEvent, B_STICKY_EVENT); }