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