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