[haiku-commits] BRANCH axeld-github.launch_daemon [9539843dbfba] src/servers/launch

  • From: axeld-github.launch_daemon <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 2 Jun 2015 11:32:11 +0200 (CEST)

added 3 changesets to branch 'refs/remotes/axeld-github/launch_daemon'
old head: bb37de24ab6377e4be019c5110d8036947205de8
new head: 9539843dbfba9b2c2e54e6cb2a51eea59227df06
overview: https://github.com/axeld/haiku/compare/bb37de24ab63...9539843dbfba

----------------------------------------------------------------------------

c688c2e4c6f2: launch_daemon: Added basic dependency support.

* Untested, and even incomplete, though.

5ec7cf891868: launch_daemon: Moved (Main)Worker to its own file.

9539843dbfba: launch_daemon: Merged Job with LaunchJob, cyclic dependencies.

* Job is now a BJob, and includes the former LaunchJob functionality.
* Dependencies are now resolved on init, and jobs are removed early
when they are not met (or are cyclic, which is now also detected).

[ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

4 files changed, 306 insertions(+), 214 deletions(-)
src/servers/launch/Jamfile | 1 +
src/servers/launch/LaunchDaemon.cpp | 364 +++++++++++++-------------------
src/servers/launch/Worker.cpp | 106 ++++++++++
src/servers/launch/Worker.h | 49 +++++

############################################################################

Commit: c688c2e4c6f2c36aff6f18ed598ab8eaaeabb1e5
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Jun 1 05:57:54 2015 UTC

launch_daemon: Added basic dependency support.

* Untested, and even incomplete, though.

----------------------------------------------------------------------------

diff --git a/src/servers/launch/LaunchDaemon.cpp
b/src/servers/launch/LaunchDaemon.cpp
index 7979f56..56b6c30 100644
--- a/src/servers/launch/LaunchDaemon.cpp
+++ b/src/servers/launch/LaunchDaemon.cpp
@@ -47,6 +47,7 @@ const static settings_template kJobTemplate[] = {
{B_STRING_TYPE, "name", NULL, true},
{B_BOOL_TYPE, "disabled", NULL},
{B_STRING_TYPE, "launch", NULL},
+ {B_STRING_TYPE, "requires", NULL},
{B_BOOL_TYPE, "legacy", NULL},
{B_MESSAGE_TYPE, "port", kPortTemplate},
{B_BOOL_TYPE, "no_safemode", NULL},
@@ -88,6 +89,10 @@ public:
BStringList& Arguments();
void AddArgument(const char*
argument);

+ const BStringList& Requirements() const;
+ BStringList& Requirements();
+ void AddRequirement(const
char* requirement);
+
status_t Init();
status_t InitCheck() const;

@@ -102,6 +107,7 @@ public:
private:
BString fName;
BStringList fArguments;
+ BStringList fRequirements;
bool fEnabled;
bool fService;
bool fCreateDefaultPort;
@@ -187,7 +193,7 @@ private:
Job* _Job(const char* name);
void _InitJobs();
void _LaunchJobs();
- void _AddLaunchJob(Job* job);
+ LaunchJob* _AddLaunchJob(Job* job);

void
_RetrieveKernelOptions();
void _SetupEnvironment();
@@ -342,6 +348,27 @@ Job::AddArgument(const char* argument)
}


+const BStringList&
+Job::Requirements() const
+{
+ return fRequirements;
+}
+
+
+BStringList&
+Job::Requirements()
+{
+ return fRequirements;
+}
+
+
+void
+Job::AddRequirement(const char* requirement)
+{
+ fRequirements.Add(requirement);
+}
+
+
status_t
Job::Init()
{
@@ -778,6 +805,13 @@ LaunchDaemon::_AddJob(bool service, BMessage& message)
job->AddArgument(argument);
}

+ const char* requirement;
+ for (int32 index = 0;
+ message.FindString("requires", index, &requirement) ==
B_OK;
+ index++) {
+ job->AddRequirement(requirement);
+ }
+
fJobs.insert(std::pair<BString, Job*>(job->Name(), job));
}

@@ -820,11 +854,11 @@ LaunchDaemon::_LaunchJobs()
}


-void
+LaunchJob*
LaunchDaemon::_AddLaunchJob(Job* job)
{
if (job->IsLaunched())
- return;
+ return NULL;

LaunchJob* launchJob = new LaunchJob(job);

@@ -832,7 +866,19 @@ LaunchDaemon::_AddLaunchJob(Job* job)
if (fInitTarget->State() < B_JOB_STATE_SUCCEEDED)
launchJob->AddDependency(fInitTarget);

+ for (int32 index = 0; index < job->Requirements().CountStrings();
index++) {
+ Job* dependency = _Job(job->Requirements().StringAt(index));
+ if (dependency != NULL) {
+ // Create launch job
+ // TODO: detect circular dependencies!
+ LaunchJob* dependentLaunchJob =
_AddLaunchJob(dependency);
+ if (dependentLaunchJob != NULL)
+ launchJob->AddDependency(dependentLaunchJob);
+ }
+ }
+
fJobQueue.AddJob(launchJob);
+ return launchJob;
}



############################################################################

Commit: 5ec7cf891868bfc3c513a7d237f9dd9cbbcfec6a
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Jun 1 14:37:47 2015 UTC

launch_daemon: Moved (Main)Worker to its own file.

----------------------------------------------------------------------------

diff --git a/src/servers/launch/Jamfile b/src/servers/launch/Jamfile
index 0ba38ee..e0fd5a1 100644
--- a/src/servers/launch/Jamfile
+++ b/src/servers/launch/Jamfile
@@ -6,6 +6,7 @@ UsePrivateSystemHeaders ;
Server launch_daemon
:
LaunchDaemon.cpp
+ Worker.cpp

# init jobs
AbstractEmptyDirectoryJob.cpp
diff --git a/src/servers/launch/LaunchDaemon.cpp
b/src/servers/launch/LaunchDaemon.cpp
index 56b6c30..27c8ec0 100644
--- a/src/servers/launch/LaunchDaemon.cpp
+++ b/src/servers/launch/LaunchDaemon.cpp
@@ -21,16 +21,16 @@

#include <AppMisc.h>
#include <DriverSettingsMessageAdapter.h>
-#include <JobQueue.h>
#include <LaunchDaemonDefs.h>
#include <syscalls.h>

#include "InitRealTimeClockJob.h"
#include "InitSharedMemoryDirectoryJob.h"
#include "InitTemporaryDirectoryJob.h"
+#include "Worker.h"


-using namespace BPrivate;
+using namespace ::BPrivate;
using namespace BSupportKit;
using BSupportKit::BPrivate::JobQueue;

@@ -139,38 +139,6 @@ protected:
};


-class Worker {
-public:
-
Worker(JobQueue& queue);
- virtual ~Worker();
-
-protected:
- virtual status_t Process();
- virtual bigtime_t Timeout() const;
- virtual status_t Run(BJob* job);
-
-private:
- static status_t _Process(void* self);
-
-protected:
- thread_id fThread;
- JobQueue& fJobQueue;
-};
-
-
-class MainWorker : public Worker {
-public:
-
MainWorker(JobQueue& queue);
-
-protected:
- virtual bigtime_t Timeout() const;
- virtual status_t Run(BJob* job);
-
-private:
- int32 fCPUCount;
-};
-
-
typedef std::map<BString, Job*> JobMap;


@@ -211,12 +179,6 @@ private:
};


-static const bigtime_t kWorkerTimeout = 1000000;
- // One second until a worker thread quits without a job
-
-static int32 sWorkerCount;
-
-
static const char*
get_leaf(const char* signature)
{
@@ -534,102 +496,6 @@ Target::Execute()
// #pragma mark -


-Worker::Worker(JobQueue& queue)
- :
- fJobQueue(queue)
-{
- fThread = spawn_thread(&Worker::_Process, "worker", B_NORMAL_PRIORITY,
- this);
- if (fThread >= 0 && resume_thread(fThread) == B_OK)
- atomic_add(&sWorkerCount, 1);
-}
-
-
-Worker::~Worker()
-{
-}
-
-
-status_t
-Worker::Process()
-{
- while (true) {
- BJob* job;
- status_t status = fJobQueue.Pop(Timeout(), false, &job);
- if (status != B_OK)
- return status;
-
- Run(job);
- // TODO: proper error reporting on failed job!
- }
-}
-
-
-bigtime_t
-Worker::Timeout() const
-{
- return kWorkerTimeout;
-}
-
-
-status_t
-Worker::Run(BJob* job)
-{
- return job->Run();
-}
-
-
-/*static*/ status_t
-Worker::_Process(void* _self)
-{
- Worker* self = (Worker*)_self;
- status_t status = self->Process();
- delete self;
-
- return status;
-}
-
-
-// #pragma mark -
-
-
-MainWorker::MainWorker(JobQueue& queue)
- :
- Worker(queue)
-{
- // TODO: keep track of workers, and quit them on destruction
- system_info info;
- if (get_system_info(&info) == B_OK)
- fCPUCount = info.cpu_count;
-}
-
-
-bigtime_t
-MainWorker::Timeout() const
-{
- return B_INFINITE_TIMEOUT;
-}
-
-
-status_t
-MainWorker::Run(BJob* job)
-{
- int32 count = atomic_get(&sWorkerCount);
-
- size_t jobCount = fJobQueue.CountJobs();
- if (jobCount > INT_MAX)
- jobCount = INT_MAX;
-
- if ((int32)jobCount > count && count < fCPUCount)
- new Worker(fJobQueue);
-
- return Worker::Run(job);
-}
-
-
-// #pragma mark -
-
-
LaunchDaemon::LaunchDaemon(status_t& error)
:
BServer(kLaunchDaemonSignature, NULL,
diff --git a/src/servers/launch/Worker.cpp b/src/servers/launch/Worker.cpp
new file mode 100644
index 0000000..c21d8fb
--- /dev/null
+++ b/src/servers/launch/Worker.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "Worker.h"
+
+
+static const bigtime_t kWorkerTimeout = 1000000;
+ // One second until a worker thread quits without a job
+
+static int32 sWorkerCount;
+
+
+Worker::Worker(JobQueue& queue)
+ :
+ fJobQueue(queue)
+{
+ fThread = spawn_thread(&Worker::_Process, "worker", B_NORMAL_PRIORITY,
+ this);
+ if (fThread >= 0 && resume_thread(fThread) == B_OK)
+ atomic_add(&sWorkerCount, 1);
+}
+
+
+Worker::~Worker()
+{
+}
+
+
+status_t
+Worker::Process()
+{
+ while (true) {
+ BJob* job;
+ status_t status = fJobQueue.Pop(Timeout(), false, &job);
+ if (status != B_OK)
+ return status;
+
+ Run(job);
+ // TODO: proper error reporting on failed job!
+ }
+}
+
+
+bigtime_t
+Worker::Timeout() const
+{
+ return kWorkerTimeout;
+}
+
+
+status_t
+Worker::Run(BJob* job)
+{
+ return job->Run();
+}
+
+
+/*static*/ status_t
+Worker::_Process(void* _self)
+{
+ Worker* self = (Worker*)_self;
+ status_t status = self->Process();
+ delete self;
+
+ return status;
+}
+
+
+// #pragma mark -
+
+
+MainWorker::MainWorker(JobQueue& queue)
+ :
+ Worker(queue)
+{
+ // TODO: keep track of workers, and quit them on destruction
+ system_info info;
+ if (get_system_info(&info) == B_OK)
+ fCPUCount = info.cpu_count;
+}
+
+
+bigtime_t
+MainWorker::Timeout() const
+{
+ return B_INFINITE_TIMEOUT;
+}
+
+
+status_t
+MainWorker::Run(BJob* job)
+{
+ int32 count = atomic_get(&sWorkerCount);
+
+ size_t jobCount = fJobQueue.CountJobs();
+ if (jobCount > INT_MAX)
+ jobCount = INT_MAX;
+
+ if ((int32)jobCount > count && count < fCPUCount)
+ new Worker(fJobQueue);
+
+ return Worker::Run(job);
+}
diff --git a/src/servers/launch/Worker.h b/src/servers/launch/Worker.h
new file mode 100644
index 0000000..bcc3e28
--- /dev/null
+++ b/src/servers/launch/Worker.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef WORKER_H
+#define WORKER_H
+
+
+#include <Job.h>
+#include <JobQueue.h>
+
+
+using namespace BSupportKit;
+using BSupportKit::BPrivate::JobQueue;
+
+
+class Worker {
+public:
+
Worker(JobQueue& queue);
+ virtual ~Worker();
+
+protected:
+ virtual status_t Process();
+ virtual bigtime_t Timeout() const;
+ virtual status_t Run(BJob* job);
+
+private:
+ static status_t _Process(void* self);
+
+protected:
+ thread_id fThread;
+ JobQueue& fJobQueue;
+};
+
+
+class MainWorker : public Worker {
+public:
+
MainWorker(JobQueue& queue);
+
+protected:
+ virtual bigtime_t Timeout() const;
+ virtual status_t Run(BJob* job);
+
+private:
+ int32 fCPUCount;
+};
+
+
+#endif // WORKER_H

############################################################################

Commit: 9539843dbfba9b2c2e54e6cb2a51eea59227df06
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Tue Jun 2 07:12:45 2015 UTC

launch_daemon: Merged Job with LaunchJob, cyclic dependencies.

* Job is now a BJob, and includes the former LaunchJob functionality.
* Dependencies are now resolved on init, and jobs are removed early
when they are not met (or are cyclic, which is now also detected).

----------------------------------------------------------------------------

diff --git a/src/servers/launch/LaunchDaemon.cpp
b/src/servers/launch/LaunchDaemon.cpp
index 27c8ec0..432c8ca 100644
--- a/src/servers/launch/LaunchDaemon.cpp
+++ b/src/servers/launch/LaunchDaemon.cpp
@@ -5,6 +5,7 @@


#include <map>
+#include <set>

#include <stdio.h>
#include <stdlib.h>
@@ -64,7 +65,19 @@ const static settings_template kSettingsTemplate[] = {
typedef std::map<BString, BMessage> PortMap;


-class Job {
+class Target : public BJob {
+public:
+ Target(const
char* name);
+
+protected:
+ virtual status_t Execute();
+};
+
+
+class JobFinder;
+
+
+class Job : public BJob {
public:
Job(const char*
name);
virtual ~Job();
@@ -93,7 +106,8 @@ public:
BStringList& Requirements();
void AddRequirement(const
char* requirement);

- status_t Init();
+ status_t Init(Target* target,
const JobFinder& jobs,
+
std::set<BString>& dependencies);
status_t InitCheck() const;

team_id Team() const;
@@ -104,6 +118,9 @@ public:
status_t Launch();
bool IsLaunched() const;

+protected:
+ virtual status_t Execute();
+
private:
BString fName;
BStringList fArguments;
@@ -118,35 +135,22 @@ private:
};


-class LaunchJob : public BJob {
-public:
- LaunchJob(Job*
job);
-
-protected:
- virtual status_t Execute();
-
-private:
- Job* fJob;
-};
+typedef std::map<BString, Job*> JobMap;


-class Target : public BJob {
+class JobFinder {
public:
- Target(const
char* name);
-
-protected:
- virtual status_t Execute();
+ virtual Job* FindJob(const char* name) const
= 0;
};


-typedef std::map<BString, Job*> JobMap;
-
-
-class LaunchDaemon : public BServer {
+class LaunchDaemon : public BServer, public JobFinder {
public:

LaunchDaemon(status_t& error);
virtual ~LaunchDaemon();

+ virtual Job* FindJob(const char* name) const;
+
virtual void ReadyToRun();
virtual void MessageReceived(BMessage*
message);

@@ -158,10 +162,9 @@ private:
status_t _ReadFile(const char*
context, BEntry& entry);

void _AddJob(bool service,
BMessage& message);
- Job* _Job(const char* name);
- void _InitJobs();
+ void _InitJobs(Target*
target);
void _LaunchJobs();
- LaunchJob* _AddLaunchJob(Job* job);
+ void _AddLaunchJob(Job* job);

void
_RetrieveKernelOptions();
void _SetupEnvironment();
@@ -195,7 +198,7 @@ get_leaf(const char* signature)

Job::Job(const char* name)
:
- fName(name),
+ BJob(name),
fEnabled(true),
fService(false),
fCreateDefaultPort(false),
@@ -203,7 +206,6 @@ Job::Job(const char* name)
fInitStatus(B_NO_INIT),
fTeam(-1)
{
- fName.ToLower();
}


@@ -221,7 +223,7 @@ Job::~Job()
const char*
Job::Name() const
{
- return fName.String();
+ return Title().String();
}


@@ -332,10 +334,47 @@ Job::AddRequirement(const char* requirement)


status_t
-Job::Init()
+Job::Init(Target* target, const JobFinder& jobs,
+ std::set<BString>& dependencies)
{
+ // Only initialize the jobs once
+ if (fInitStatus != B_NO_INIT)
+ return fInitStatus;
+
fInitStatus = B_OK;

+ if (target != NULL && target->State() < B_JOB_STATE_SUCCEEDED)
+ AddDependency(target);
+
+ // Check dependencies
+
+ for (int32 index = 0; index < Requirements().CountStrings(); index++) {
+ const BString& requires = Requirements().StringAt(index);
+ if (dependencies.find(requires) != dependencies.end()) {
+ // Found a cyclic dependency
+ // TODO: log error
+ return fInitStatus = B_ERROR;
+ }
+ dependencies.insert(requires);
+
+ Job* dependency = jobs.FindJob(requires);
+ if (dependency != NULL) {
+ std::set<BString> subDependencies = dependencies;
+
+ fInitStatus = dependency->Init(target, jobs,
subDependencies);
+ if (fInitStatus != B_OK) {
+ // TODO: log error
+ return fInitStatus;
+ }
+
+ AddDependency(dependency);
+ } else {
+ // Could not find dependency
+ // TODO: log error
+ return fInitStatus = B_NAME_NOT_FOUND;
+ }
+ }
+
// Create ports
// TODO: prefix system ports with "system:"

@@ -366,9 +405,10 @@ Job::Init()
data.AddInt32("capacity", B_LOOPER_PORT_DEFAULT_CAPACITY);

port_id port = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY,
Name());
- if (port < 0)
+ if (port < 0) {
+ // TODO: log error
fInitStatus = port;
- else {
+ } else {
data.SetInt32("port", port);
AddPort(data);
}
@@ -455,22 +495,11 @@ Job::IsLaunched() const
}


-// #pragma mark -
-
-
-LaunchJob::LaunchJob(Job* job)
- :
- BJob(job->Name()),
- fJob(job)
-{
-}
-
-
status_t
-LaunchJob::Execute()
+Job::Execute()
{
- if (!fJob->IsLaunched())
- return fJob->Launch();
+ if (!IsLaunched())
+ return Launch();

return B_OK;
}
@@ -512,6 +541,20 @@ LaunchDaemon::~LaunchDaemon()
}


+Job*
+LaunchDaemon::FindJob(const char* name) const
+{
+ if (name == NULL)
+ return NULL;
+
+ JobMap::const_iterator found = fJobs.find(BString(name).ToLower());
+ if (found != fJobs.end())
+ return found->second;
+
+ return NULL;
+}
+
+
void
LaunchDaemon::ReadyToRun()
{
@@ -528,7 +571,7 @@ LaunchDaemon::ReadyToRun()
B_FIND_PATHS_SYSTEM_ONLY, paths);
_ReadPaths(paths);

- _InitJobs();
+ _InitJobs(fInitTarget);
_LaunchJobs();
}

@@ -540,7 +583,7 @@ LaunchDaemon::MessageReceived(BMessage* message)
case B_GET_LAUNCH_DATA:
{
BMessage reply((uint32)B_OK);
- Job* job = _Job(get_leaf(message->GetString("name")));
+ Job* job =
FindJob(get_leaf(message->GetString("name")));
if (job == NULL) {
reply.what = B_NAME_NOT_FOUND;
} else {
@@ -643,13 +686,14 @@ LaunchDaemon::_ReadFile(const char* context, BEntry&
entry)
void
LaunchDaemon::_AddJob(bool service, BMessage& message)
{
- const char* name = message.GetString("name");
- if (name == NULL || name[0] == '\0') {
+ BString name = message.GetString("name");
+ if (name.IsEmpty()) {
// Invalid job description
return;
}
+ name.ToLower();

- Job* job = _Job(name);
+ Job* job = FindJob(name);
if (job == NULL)
job = new Job(name);

@@ -682,28 +726,29 @@ LaunchDaemon::_AddJob(bool service, BMessage& message)
}


-Job*
-LaunchDaemon::_Job(const char* name)
+void
+LaunchDaemon::_InitJobs(Target* target)
{
- if (name == NULL)
- return NULL;
-
- JobMap::const_iterator found = fJobs.find(BString(name).ToLower());
- if (found != fJobs.end())
- return found->second;
+ for (JobMap::iterator iterator = fJobs.begin(); iterator !=
fJobs.end();) {
+ Job* job = iterator->second;
+ JobMap::iterator remove = iterator++;

- return NULL;
-}
+ status_t status = B_NO_INIT;
+ if (job->IsEnabled() && (!_IsSafeMode() ||
job->LaunchInSafeMode())) {
+ std::set<BString> dependencies;
+ status = job->Init(target, *this, dependencies);
+ }

+ if (status != B_OK) {
+ if (status != B_NO_INIT) {
+ // TODO: log error
+ debug_printf("Init \"%s\" failed: %s\n",
job->Name(),
+ strerror(status));
+ }

-void
-LaunchDaemon::_InitJobs()
-{
- for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
- iterator++) {
- Job* job = iterator->second;
- if (job->IsEnabled() && (!_IsSafeMode() ||
job->LaunchInSafeMode()))
- job->Init();
+ // Remove jobs that aren't user later on
+ fJobs.erase(remove);
+ }
}
}

@@ -714,37 +759,16 @@ LaunchDaemon::_LaunchJobs()
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
iterator++) {
Job* job = iterator->second;
- if (job->IsEnabled() && job->InitCheck() == B_OK)
- _AddLaunchJob(job);
+ _AddLaunchJob(job);
}
}


-LaunchJob*
+void
LaunchDaemon::_AddLaunchJob(Job* job)
{
- if (job->IsLaunched())
- return NULL;
-
- LaunchJob* launchJob = new LaunchJob(job);
-
- // All jobs depend on the init target
- if (fInitTarget->State() < B_JOB_STATE_SUCCEEDED)
- launchJob->AddDependency(fInitTarget);
-
- for (int32 index = 0; index < job->Requirements().CountStrings();
index++) {
- Job* dependency = _Job(job->Requirements().StringAt(index));
- if (dependency != NULL) {
- // Create launch job
- // TODO: detect circular dependencies!
- LaunchJob* dependentLaunchJob =
_AddLaunchJob(dependency);
- if (dependentLaunchJob != NULL)
- launchJob->AddDependency(dependentLaunchJob);
- }
- }
-
- fJobQueue.AddJob(launchJob);
- return launchJob;
+ if (!job->IsLaunched())
+ fJobQueue.AddJob(job);
}




Other related posts:

  • » [haiku-commits] BRANCH axeld-github.launch_daemon [9539843dbfba] src/servers/launch - axeld-github . launch_daemon