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