1/* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5#ifndef WORKER_H 6#define WORKER_H 7 8#include <Locker.h> 9 10#include <ObjectList.h> 11#include <Referenceable.h> 12#include <util/DoublyLinkedList.h> 13#include <util/OpenHashTable.h> 14 15 16class Job; 17class Worker; 18 19 20enum job_state { 21 JOB_STATE_UNSCHEDULED, 22 JOB_STATE_WAITING, 23 JOB_STATE_ACTIVE, 24 JOB_STATE_ABORTED, 25 JOB_STATE_FAILED, 26 JOB_STATE_SUCCEEDED 27}; 28 29enum job_wait_status { 30 JOB_DEPENDENCY_NOT_FOUND, 31 JOB_DEPENDENCY_SUCCEEDED, 32 JOB_DEPENDENCY_FAILED, 33 JOB_DEPENDENCY_ABORTED, 34 JOB_DEPENDENCY_ACTIVE 35 // internal only 36}; 37 38 39class JobKey { 40public: 41 virtual ~JobKey(); 42 43 virtual size_t HashValue() const = 0; 44 45 virtual bool operator==(const JobKey& other) const = 0; 46}; 47 48 49struct SimpleJobKey : public JobKey { 50 void* object; 51 uint32 type; 52 53public: 54 SimpleJobKey(void* object, uint32 type); 55 SimpleJobKey(const SimpleJobKey& other); 56 57 virtual size_t HashValue() const; 58 59 virtual bool operator==(const JobKey& other) const; 60 61 SimpleJobKey& operator=(const SimpleJobKey& other); 62}; 63 64 65class JobListener { 66public: 67 virtual ~JobListener(); 68 69 virtual void JobDone(Job* job); 70 virtual void JobFailed(Job* job); 71 virtual void JobAborted(Job* job); 72}; 73 74 75typedef DoublyLinkedList<Job> JobList; 76 77 78class Job : public BReferenceable, public DoublyLinkedListLinkImpl<Job> { 79public: 80 Job(); 81 virtual ~Job(); 82 83 virtual const JobKey& Key() const = 0; 84 virtual status_t Do() = 0; 85 86 Worker* GetWorker() const { return fWorker; } 87 job_state State() const { return fState; } 88 89protected: 90 job_wait_status WaitFor(const JobKey& key); 91 92private: 93 friend class Worker; 94 95private: 96 void SetWorker(Worker* worker); 97 void SetState(job_state state); 98 99 Job* Dependency() const { return fDependency; } 100 void SetDependency(Job* job); 101 102 JobList& DependentJobs() { return fDependentJobs; } 103 104 job_wait_status WaitStatus() const { return fWaitStatus; } 105 void SetWaitStatus(job_wait_status status); 106 107 status_t AddListener(JobListener* listener); 108 void RemoveListener(JobListener* listener); 109 void NotifyListeners(); 110 111private: 112 typedef BObjectList<JobListener> ListenerList; 113 114private: 115 Worker* fWorker; 116 job_state fState; 117 Job* fDependency; 118 JobList fDependentJobs; 119 job_wait_status fWaitStatus; 120 ListenerList fListeners; 121 122public: 123 Job* fNext; 124}; 125 126 127class Worker { 128public: 129 Worker(); 130 ~Worker(); 131 132 status_t Init(); 133 void ShutDown(); 134 135 bool Lock() { return fLock.Lock(); } 136 void Unlock() { fLock.Unlock(); } 137 138 status_t ScheduleJob(Job* job, 139 JobListener* listener = NULL); 140 // always takes over reference 141 void AbortJob(const JobKey& key); 142 Job* GetJob(const JobKey& key); 143 144 status_t AddListener(const JobKey& key, 145 JobListener* listener); 146 void RemoveListener(const JobKey& key, 147 JobListener* listener); 148 149private: 150 friend class Job; 151 152 struct JobHashDefinition { 153 typedef JobKey KeyType; 154 typedef Job ValueType; 155 156 size_t HashKey(const JobKey& key) const 157 { 158 return key.HashValue(); 159 } 160 161 size_t Hash(Job* value) const 162 { 163 return HashKey(value->Key()); 164 } 165 166 bool Compare(const JobKey& key, Job* value) const 167 { 168 return value->Key() == key; 169 } 170 171 Job*& GetLink(Job* value) const 172 { 173 return value->fNext; 174 } 175 }; 176 177 typedef BOpenHashTable<JobHashDefinition> JobTable; 178 179private: 180 job_wait_status WaitForJob(Job* waitingJob, const JobKey& key); 181 182 static status_t _WorkerLoopEntry(void* data); 183 status_t _WorkerLoop(); 184 185 void _ProcessJobs(); 186 void _AbortJob(Job* job, bool removeFromTable); 187 void _FinishJob(Job* job); 188 189private: 190 BLocker fLock; 191 JobTable fJobs; 192 JobList fUnscheduledJobs; 193 JobList fAbortedJobs; 194 sem_id fWorkToDoSem; 195 thread_id fWorkerThread; 196 volatile bool fTerminating; 197}; 198 199 200#endif // WORKER_H 201