[Haiku-commits] r31116 - haiku/trunk/src/apps/debugger
bonefish at BerliOS
bonefish at mail.berlios.de
Fri Jun 19 17:09:56 CEST 2009
Author: bonefish
Date: 2009-06-19 17:09:56 +0200 (Fri, 19 Jun 2009)
New Revision: 31116
ViewCVS: http://svn.berlios.de/viewcvs/haiku?rev=31116&view=rev
Added:
haiku/trunk/src/apps/debugger/Jobs.cpp
haiku/trunk/src/apps/debugger/Jobs.h
haiku/trunk/src/apps/debugger/Worker.cpp
haiku/trunk/src/apps/debugger/Worker.h
Modified:
haiku/trunk/src/apps/debugger/Jamfile
haiku/trunk/src/apps/debugger/TeamDebugger.cpp
haiku/trunk/src/apps/debugger/TeamDebugger.h
Log:
* Implemented Worker class, which executes Jobs in a separate thread.
* Implemented a job for getting a thread's CPU state.
* The team debugger uses a worker now. ATM only for getting the CPU state for
stopped threads.
Modified: haiku/trunk/src/apps/debugger/Jamfile
===================================================================
--- haiku/trunk/src/apps/debugger/Jamfile 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/Jamfile 2009-06-19 15:09:56 UTC (rev 31116)
@@ -23,11 +23,13 @@
# ElfFile.cpp
Image.cpp
ImageInfo.cpp
+ Jobs.cpp
Team.cpp
TeamDebugger.cpp
TeamDebugModel.cpp
Thread.cpp
ThreadInfo.cpp
+ Worker.cpp
# arch
Architecture.cpp
Added: haiku/trunk/src/apps/debugger/Jobs.cpp
===================================================================
--- haiku/trunk/src/apps/debugger/Jobs.cpp 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/Jobs.cpp 2009-06-19 15:09:56 UTC (rev 31116)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2009, Ingo Weinhold, ingo_weinhold at gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+#include "Jobs.h"
+
+#include <AutoLocker.h>
+
+#include "CpuState.h"
+#include "DebuggerInterface.h"
+#include "Team.h"
+#include "Thread.h"
+
+
+GetCpuStateJob::GetCpuStateJob(DebuggerInterface* debuggerInterface,
+ Thread* thread)
+ :
+ fDebuggerInterface(debuggerInterface),
+ fThread(thread)
+{
+ fThread->AddReference();
+}
+
+
+GetCpuStateJob::~GetCpuStateJob()
+{
+ fThread->RemoveReference();
+}
+
+
+JobKey
+GetCpuStateJob::Key() const
+{
+ return JobKey(fThread, JOB_TYPE_GET_CPU_STATE);
+}
+
+
+status_t
+GetCpuStateJob::Do()
+{
+ CpuState* state;
+ status_t error = fDebuggerInterface->GetCpuState(fThread->ID(), state);
+ if (error != B_OK)
+ return error;
+ Reference<CpuState> reference(state);
+
+ AutoLocker<Team> locker(fThread->GetTeam());
+
+ if (fThread->State() == THREAD_STATE_STOPPED)
+ fThread->SetCpuState(state);
+
+ return B_OK;
+}
Added: haiku/trunk/src/apps/debugger/Jobs.h
===================================================================
--- haiku/trunk/src/apps/debugger/Jobs.h 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/Jobs.h 2009-06-19 15:09:56 UTC (rev 31116)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009, Ingo Weinhold, ingo_weinhold at gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef JOBS_H
+#define JOBS_H
+
+#include "Worker.h"
+
+
+class DebuggerInterface;
+class Thread;
+
+
+// job types
+enum {
+ JOB_TYPE_GET_CPU_STATE
+};
+
+
+class GetCpuStateJob : public Job {
+public:
+ GetCpuStateJob(
+ DebuggerInterface* debuggerInterface,
+ Thread* thread);
+ virtual ~GetCpuStateJob();
+
+ virtual JobKey Key() const;
+ virtual status_t Do();
+
+private:
+ DebuggerInterface* fDebuggerInterface;
+ Thread* fThread;
+};
+
+
+#endif // JOBS_H
Modified: haiku/trunk/src/apps/debugger/TeamDebugger.cpp
===================================================================
--- haiku/trunk/src/apps/debugger/TeamDebugger.cpp 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/TeamDebugger.cpp 2009-06-19 15:09:56 UTC (rev 31116)
@@ -17,6 +17,7 @@
#include "CpuState.h"
#include "DebuggerInterface.h"
+#include "Jobs.h"
#include "MessageCodes.h"
#include "Team.h"
#include "TeamDebugModel.h"
@@ -29,6 +30,7 @@
fDebugModel(NULL),
fTeamID(-1),
fDebuggerInterface(NULL),
+ fWorker(NULL),
fDebugEventListener(-1),
fTeamWindow(NULL),
fTerminating(false)
@@ -43,15 +45,17 @@
fTerminating = true;
fDebuggerInterface->Close();
+ fWorker->ShutDown();
locker.Unlock();
if (fDebugEventListener >= 0)
wait_for_thread(fDebugEventListener, NULL);
+ delete fDebuggerInterface;
+ delete fWorker;
delete fDebugModel;
delete fTeam;
- delete fDebuggerInterface;
}
@@ -86,6 +90,15 @@
if (error != B_OK)
return error;
+ // create our worker
+ fWorker = new(std::nothrow) Worker;
+ if (fWorker == NULL)
+ return B_NO_MEMORY;
+
+ error = fWorker->Init();
+ if (error != B_OK)
+ return error;
+
// create debugger interface
fDebuggerInterface = new(std::nothrow) DebuggerInterface(fTeamID);
if (fDebuggerInterface == NULL)
@@ -207,6 +220,27 @@
}
+void
+TeamDebugger::JobDone(Job* job)
+{
+printf("TeamDebugger::JobDone(%p)\n", job);
+}
+
+
+void
+TeamDebugger::JobFailed(Job* job)
+{
+printf("TeamDebugger::JobFailed(%p)\n", job);
+}
+
+
+void
+TeamDebugger::JobAborted(Job* job)
+{
+printf("TeamDebugger::JobAborted(%p)\n", job);
+}
+
+
/*static*/ status_t
TeamDebugger::_DebugEventListenerEntry(void* data)
{
@@ -335,15 +369,8 @@
if (thread == NULL)
return false;
- // update the thread state
- thread->SetState(THREAD_STATE_STOPPED);
+ _SetThreadState(thread, THREAD_STATE_STOPPED, cpuState);
- if (cpuState != NULL) {
- thread->SetCpuState(cpuState);
- } else {
- // TODO: Trigger updating the CPU state!
- }
-
return true;
}
@@ -435,22 +462,46 @@
void
TeamDebugger::_UpdateThreadState(::Thread* thread)
{
- CpuState* state = NULL;
- status_t error = fDebuggerInterface->GetCpuState(thread->ID(), state);
+ CpuState* cpuState = NULL;
+ status_t error = fDebuggerInterface->GetCpuState(thread->ID(), cpuState);
uint32 newState = THREAD_STATE_UNKNOWN;
if (error == B_OK) {
newState = THREAD_STATE_STOPPED;
- state->RemoveReference();
+ cpuState->RemoveReference();
} else if (error == B_BAD_THREAD_STATE)
newState = THREAD_STATE_RUNNING;
- thread->SetState(newState);
- thread->SetCpuState(state);
+ _SetThreadState(thread, newState, cpuState);
}
void
+TeamDebugger::_SetThreadState(::Thread* thread, uint32 state,
+ CpuState* cpuState)
+{
+ // update the thread state
+ uint32 oldState = thread->State();
+ thread->SetState(state);
+
+ // cancel jobs for this thread
+ if (oldState == THREAD_STATE_STOPPED)
+ fWorker->AbortJob(JobKey(thread, JOB_TYPE_GET_CPU_STATE));
+
+ if (state == THREAD_STATE_STOPPED) {
+ if (cpuState != NULL) {
+ thread->SetCpuState(cpuState);
+ } else {
+ // trigger updating the CPU state
+ fWorker->ScheduleJob(new(std::nothrow) GetCpuStateJob(
+ fDebuggerInterface, thread),
+ this);
+ }
+ }
+}
+
+
+void
TeamDebugger::_HandleThreadAction(thread_id threadID, uint32 action)
{
AutoLocker< ::Team> locker(fTeam);
@@ -469,7 +520,7 @@
// When continuing the thread update thread state before actually issuing
// the command, since we need to unlock.
if (action != MSG_THREAD_STOP)
- thread->SetState(THREAD_STATE_RUNNING);
+ _SetThreadState(thread, THREAD_STATE_RUNNING, NULL);
locker.Unlock();
Modified: haiku/trunk/src/apps/debugger/TeamDebugger.h
===================================================================
--- haiku/trunk/src/apps/debugger/TeamDebugger.h 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/TeamDebugger.h 2009-06-19 15:09:56 UTC (rev 31116)
@@ -13,6 +13,7 @@
#include "DebugEvent.h"
#include "TeamWindow.h"
+#include "Worker.h"
class DebuggerInterface;
@@ -21,7 +22,7 @@
class TeamDebugger : public DoublyLinkedListLinkImpl<TeamDebugger>,
- private BLooper, private TeamWindow::Listener {
+ private BLooper, private TeamWindow::Listener, private JobListener {
public:
TeamDebugger();
~TeamDebugger();
@@ -39,6 +40,11 @@
thread_id threadID, uint32 action);
virtual bool TeamWindowQuitRequested(TeamWindow* window);
+ // JobListener
+ virtual void JobDone(Job* job);
+ virtual void JobFailed(Job* job);
+ virtual void JobAborted(Job* job);
+
private:
static status_t _DebugEventListenerEntry(void* data);
status_t _DebugEventListener();
@@ -70,6 +76,8 @@
ImageDeletedEvent* event);
void _UpdateThreadState(::Thread* thread);
+ void _SetThreadState(::Thread* thread, uint32 state,
+ CpuState* cpuState);
void _HandleThreadAction(thread_id threadID,
uint32 action);
@@ -80,6 +88,7 @@
team_id fTeamID;
port_id fNubPort;
DebuggerInterface* fDebuggerInterface;
+ Worker* fWorker;
thread_id fDebugEventListener;
TeamWindow* fTeamWindow;
volatile bool fTerminating;
Added: haiku/trunk/src/apps/debugger/Worker.cpp
===================================================================
--- haiku/trunk/src/apps/debugger/Worker.cpp 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/Worker.cpp 2009-06-19 15:09:56 UTC (rev 31116)
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2009, Ingo Weinhold, ingo_weinhold at gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+#include "Worker.h"
+
+#include <AutoDeleter.h>
+#include <AutoLocker.h>
+
+
+// #pragma mark - JobListener
+
+
+JobListener::~JobListener()
+{
+}
+
+
+void
+JobListener::JobDone(Job* job)
+{
+}
+
+
+void
+JobListener::JobFailed(Job* job)
+{
+}
+
+
+void
+JobListener::JobAborted(Job* job)
+{
+}
+
+
+// #pragma mark - Job
+
+
+Job::Job()
+ :
+ fWorker(NULL),
+ fState(JOB_STATE_UNSCHEDULED),
+ fDependency(NULL),
+ fWaitStatus(JOB_DEPENDENCY_NOT_FOUND),
+ fListeners(10)
+{
+}
+
+
+Job::~Job()
+{
+}
+
+
+job_wait_status
+Job::WaitFor(const JobKey& key)
+{
+ return fWorker->WaitForJob(this, key);
+}
+
+
+void
+Job::SetWorker(Worker* worker)
+{
+ fWorker = worker;
+}
+
+
+void
+Job::SetState(job_state state)
+{
+ fState = state;
+}
+
+
+void
+Job::SetDependency(Job* job)
+{
+ fDependency = job;
+}
+
+
+void
+Job::SetWaitStatus(job_wait_status status)
+{
+ fWaitStatus = status;
+}
+
+
+status_t
+Job::AddListener(JobListener* listener)
+{
+ return fListeners.AddItem(listener) ? B_OK : B_NO_MEMORY;
+}
+
+
+void
+Job::RemoveListener(JobListener* listener)
+{
+ fListeners.RemoveItem(listener);
+}
+
+
+void
+Job::NotifyListeners()
+{
+ int32 count = fListeners.CountItems();
+ for (int32 i = count - 1; i >= 0; i--) {
+ JobListener* listener = fListeners.ItemAt(i);
+ switch (fState) {
+ case JOB_STATE_SUCCEEDED:
+ listener->JobDone(this);
+ break;
+ case JOB_STATE_FAILED:
+ listener->JobFailed(this);
+ break;
+ case JOB_STATE_ABORTED:
+ default:
+ listener->JobAborted(this);
+ break;
+ }
+ }
+}
+
+
+// #pragma mark - Worker
+
+
+Worker::Worker()
+ :
+ fLock("worker"),
+ fWorkerThread(-1),
+ fTerminating(false)
+{
+}
+
+
+Worker::~Worker()
+{
+ ShutDown();
+
+ if (fWorkerThread >= 0)
+ wait_for_thread(fWorkerThread, NULL);
+}
+
+
+status_t
+Worker::Init()
+{
+ // check lock
+ status_t error = fLock.InitCheck();
+ if (error != B_OK)
+ return error;
+
+ // init jobs table
+ error = fJobs.Init();
+ if (error != B_OK)
+ return error;
+
+ // create semaphore for the worker
+ fWorkToDoSem = create_sem(0, "work to do");
+ if (fWorkToDoSem < 0)
+ return fWorkToDoSem;
+
+ // spawn worker thread
+ fWorkerThread = spawn_thread(_WorkerLoopEntry, "worker", B_NORMAL_PRIORITY,
+ this);
+ if (fWorkerThread < 0)
+ return fWorkerThread;
+
+ resume_thread(fWorkerThread);
+
+ return B_OK;
+}
+
+
+void
+Worker::ShutDown()
+{
+ AutoLocker<Worker> locker(this);
+
+ if (fTerminating)
+ return;
+
+ fTerminating = true;
+
+ // abort all jobs
+ Job* job = fJobs.Clear(true);
+ while (job != NULL) {
+ Job* nextJob = static_cast<HashTableLink<Job>*>(job)->fNext;
+ _AbortJob(job, false);
+ job = nextJob;
+
+ }
+
+ // let the work thread terminate
+ delete_sem(fWorkToDoSem);
+ fWorkToDoSem = -1;
+}
+
+
+status_t
+Worker::ScheduleJob(Job* job, JobListener* listener)
+{
+ if (job == NULL)
+ return B_NO_MEMORY;
+
+ ObjectDeleter<Job> jobDeleter(job);
+ AutoLocker<Worker> locker(this);
+
+ if (fTerminating)
+ return B_ERROR;
+
+ if (listener != NULL) {
+ status_t error = job->AddListener(listener);
+ if (error != B_OK)
+ return error;
+ }
+
+ bool notify = fUnscheduledJobs.IsEmpty() && fAbortedJobs.IsEmpty();
+
+ job->SetWorker(this);
+ job->SetState(JOB_STATE_UNSCHEDULED);
+ fJobs.Insert(job);
+ fUnscheduledJobs.Add(job);
+ jobDeleter.Detach();
+
+ if (notify)
+ release_sem(fWorkToDoSem);
+
+ return B_OK;
+}
+
+
+void
+Worker::AbortJob(const JobKey& key)
+{
+ AutoLocker<Worker> locker(this);
+
+ Job* job = fJobs.Lookup(key);
+ if (job == NULL)
+ return;
+
+ _AbortJob(job, true);
+}
+
+
+status_t
+Worker::AddListener(const JobKey& key, JobListener* listener)
+{
+ AutoLocker<Worker> locker(this);
+
+ Job* job = fJobs.Lookup(key);
+ if (job == NULL)
+ return B_ENTRY_NOT_FOUND;
+
+ return job->AddListener(listener);
+}
+
+
+void
+Worker::RemoveListener(const JobKey& key, JobListener* listener)
+{
+ AutoLocker<Worker> locker(this);
+
+ if (Job* job = fJobs.Lookup(key))
+ job->RemoveListener(listener);
+}
+
+
+job_wait_status
+Worker::WaitForJob(Job* waitingJob, const JobKey& key)
+{
+ AutoLocker<Worker> locker(this);
+
+ // don't wait when the game is over anyway
+ if (fTerminating || waitingJob->State() == JOB_STATE_ABORTED)
+ return JOB_DEPENDENCY_ABORTED;
+
+ Job* job = fJobs.Lookup(key);
+ if (job == NULL)
+ return JOB_DEPENDENCY_NOT_FOUND;
+
+ waitingJob->SetWaitStatus(JOB_DEPENDENCY_ACTIVE);
+ waitingJob->SetDependency(job);
+ job->DependentJobs().Add(waitingJob);
+
+ // TODO: Continuations would be nice. For the time being we have to use
+ // recursion. Disadvantages are that we'll use more stack and that aborting
+ // a job waiting for a dependency won't abort the job before the dependency
+ // is done.
+ locker.Unlock();
+ _ProcessJobs(job);
+ locker.Lock();
+
+ // ignore the actual wait status when the game is over anyway
+ if (fTerminating || waitingJob->State() == JOB_STATE_ABORTED)
+ return JOB_DEPENDENCY_ABORTED;
+
+ return waitingJob->WaitStatus();
+}
+
+
+/*static*/ status_t
+Worker::_WorkerLoopEntry(void* data)
+{
+ return ((Worker*)data)->_WorkerLoop();
+}
+
+
+status_t
+Worker::_WorkerLoop()
+{
+ _ProcessJobs(NULL);
+
+ // clean up aborted jobs
+ AutoLocker<Worker> locker(this);
+ while (Job* job = fAbortedJobs.RemoveHead())
+ _FinishJob(job);
+
+ return B_OK;
+}
+
+
+void
+Worker::_ProcessJobs(Job* finalJob)
+{
+ while (true) {
+ AutoLocker<Worker> locker(this);
+
+ // wait for next job
+ if (fUnscheduledJobs.IsEmpty() && fAbortedJobs.IsEmpty()) {
+ locker.Unlock();
+
+ status_t error = acquire_sem(fWorkToDoSem);
+ if (error != B_OK) {
+ if (error == B_INTERRUPTED)
+ continue;
+ break;
+ }
+
+ locker.Lock();
+ }
+
+ // clean up aborted jobs
+ while (Job* job = fAbortedJobs.RemoveHead()) {
+ _FinishJob(job);
+
+ if (job == finalJob)
+ break;
+ }
+
+ // process the next job
+ if (Job* job = fUnscheduledJobs.RemoveHead()) {
+ job->SetState(JOB_STATE_ACTIVE);
+
+ locker.Unlock();
+ status_t error = job->Do();
+ locker.Lock();
+
+ if (job->State() == JOB_STATE_ACTIVE) {
+ job->SetState(
+ error == B_OK ? JOB_STATE_SUCCEEDED : JOB_STATE_FAILED);
+ }
+
+ _FinishJob(job);
+
+ if (job == finalJob)
+ break;
+ }
+ }
+}
+
+
+void
+Worker::_AbortJob(Job* job, bool removeFromTable)
+{
+ switch (job->State()) {
+ case JOB_STATE_ABORTED:
+ return;
+
+ case JOB_STATE_UNSCHEDULED:
+ fUnscheduledJobs.Remove(job);
+ fAbortedJobs.Add(job);
+ break;
+
+ case JOB_STATE_WAITING:
+ job->Dependency()->DependentJobs().Remove(job);
+ job->SetDependency(NULL);
+ break;
+
+ case JOB_STATE_ACTIVE:
+ case JOB_STATE_FAILED:
+ case JOB_STATE_SUCCEEDED:
+ default:
+ break;
+ }
+
+ job->SetState(JOB_STATE_ABORTED);
+ if (removeFromTable)
+ fJobs.Remove(job);
+}
+
+
+void
+Worker::_FinishJob(Job* job)
+{
+ // wake up dependent jobs
+ if (!job->DependentJobs().IsEmpty()) {
+ job_wait_status waitStatus;
+ switch (job->State()) {
+ case JOB_STATE_ABORTED:
+ waitStatus = JOB_DEPENDENCY_ABORTED;
+ break;
+ case JOB_STATE_FAILED:
+ waitStatus = JOB_DEPENDENCY_FAILED;
+ break;
+ case JOB_STATE_SUCCEEDED:
+ waitStatus = JOB_DEPENDENCY_SUCCEEDED;
+ break;
+
+ case JOB_STATE_UNSCHEDULED:
+ case JOB_STATE_WAITING:
+ case JOB_STATE_ACTIVE:
+ default:
+ // should never happen
+ waitStatus = JOB_DEPENDENCY_NOT_FOUND;
+ break;
+ }
+
+ while (Job* dependentJob = job->DependentJobs().RemoveHead()) {
+ dependentJob->SetDependency(NULL);
+ dependentJob->SetWaitStatus(waitStatus);
+ }
+ }
+
+ if (job->State() != JOB_STATE_ABORTED)
+ fJobs.Remove(job);
+ job->NotifyListeners();
+ delete job;
+}
Added: haiku/trunk/src/apps/debugger/Worker.h
===================================================================
--- haiku/trunk/src/apps/debugger/Worker.h 2009-06-19 11:09:21 UTC (rev 31115)
+++ haiku/trunk/src/apps/debugger/Worker.h 2009-06-19 15:09:56 UTC (rev 31116)
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2009, Ingo Weinhold, ingo_weinhold at gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef WORKER_H
+#define WORKER_H
+
+#include <Locker.h>
+
+#include <ObjectList.h>
+#include <util/DoublyLinkedList.h>
+#include <util/OpenHashTable.h>
+
+
+class Job;
+class Worker;
+
+
+enum job_state {
+ JOB_STATE_UNSCHEDULED,
+ JOB_STATE_WAITING,
+ JOB_STATE_ACTIVE,
+ JOB_STATE_ABORTED,
+ JOB_STATE_FAILED,
+ JOB_STATE_SUCCEEDED
+};
+
+enum job_wait_status {
+ JOB_DEPENDENCY_NOT_FOUND,
+ JOB_DEPENDENCY_SUCCEEDED,
+ JOB_DEPENDENCY_FAILED,
+ JOB_DEPENDENCY_ABORTED,
+ JOB_DEPENDENCY_ACTIVE
+ // internal only
+};
+
+
+struct JobKey {
+ void* object;
+ uint32 type;
+
+ JobKey(void* object, uint32 type)
+ :
+ object(object),
+ type(type)
+ {
+ }
+
+ JobKey(const JobKey& other)
+ :
+ object(other.object),
+ type(other.type)
+ {
+ }
+
+ JobKey& operator=(const JobKey& other)
+ {
+ object = other.object;
+ type = other.type;
+ return *this;
+ }
+
+ bool operator==(const JobKey& other) const
+ {
+ return object == other.object && type == other.type;
+ }
+
+ size_t HashValue() const
+ {
+ return (size_t)(addr_t)object ^ (size_t)type;
+ }
+};
+
+
+class JobListener {
+public:
+ virtual ~JobListener();
+
+ virtual void JobDone(Job* job);
+ virtual void JobFailed(Job* job);
+ virtual void JobAborted(Job* job);
+};
+
+
+typedef DoublyLinkedList<Job> JobList;
+
+
+class Job : public DoublyLinkedListLinkImpl<Job>, public HashTableLink<Job> {
+public:
+ Job();
+ virtual ~Job();
+
+ virtual JobKey Key() const = 0;
+ virtual status_t Do() = 0;
+
+ Worker* GetWorker() const { return fWorker; }
+ job_state State() const { return fState; }
+
+protected:
+ job_wait_status WaitFor(const JobKey& key);
+
+private:
+ friend class Worker;
+
+private:
+ void SetWorker(Worker* worker);
+ void SetState(job_state state);
+
+ Job* Dependency() const { return fDependency; }
+ void SetDependency(Job* job);
+
+ JobList& DependentJobs() { return fDependentJobs; }
+
+ job_wait_status WaitStatus() const { return fWaitStatus; }
+ void SetWaitStatus(job_wait_status status);
+
+ status_t AddListener(JobListener* listener);
+ void RemoveListener(JobListener* listener);
+ void NotifyListeners();
+
+private:
+ typedef BObjectList<JobListener> ListenerList;
+
+private:
+ Worker* fWorker;
+ job_state fState;
+ Job* fDependency;
+ JobList fDependentJobs;
+ job_wait_status fWaitStatus;
+ ListenerList fListeners;
+};
+
+
+class Worker {
+public:
+ Worker();
+ ~Worker();
+
+ status_t Init();
+ void ShutDown();
+
+ bool Lock() { return fLock.Lock(); }
+ void Unlock() { fLock.Unlock(); }
+
+ status_t ScheduleJob(Job* job,
+ JobListener* listener = NULL);
+ // always takes over ownership
+ void AbortJob(const JobKey& key);
+
+ status_t AddListener(const JobKey& key,
+ JobListener* listener);
+ void RemoveListener(const JobKey& key,
+ JobListener* listener);
+
+private:
+ friend class Job;
+
+ struct JobHashDefinition {
+ typedef JobKey KeyType;
+ typedef Job ValueType;
+
+ size_t HashKey(const JobKey& key) const
+ {
+ return key.HashValue();
+ }
+
+ size_t Hash(Job* value) const
+ {
+ return HashKey(value->Key());
+ }
+
+ bool Compare(const JobKey& key, Job *value) const
+ {
+ return value->Key() == key;
+ }
+
+ HashTableLink<Job>* GetLink(Job* value) const
+ {
+ return value;
+ }
+ };
+
+ typedef OpenHashTable<JobHashDefinition> JobTable;
+
+private:
+ job_wait_status WaitForJob(Job* waitingJob, const JobKey& key);
+
+ static status_t _WorkerLoopEntry(void* data);
+ status_t _WorkerLoop();
+
+ void _ProcessJobs(Job* finalJob);
+ void _AbortJob(Job* job, bool removeFromTable);
+ void _FinishJob(Job* job);
+
+private:
+ BLocker fLock;
+ JobTable fJobs;
+ JobList fUnscheduledJobs;
+ JobList fAbortedJobs;
+ sem_id fWorkToDoSem;
+ thread_id fWorkerThread;
+ volatile bool fTerminating;
+};
+
+
+#endif // WORKER_H
More information about the Haiku-commits
mailing list