summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/JobManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/JobManager.h')
-rw-r--r--xbmc/utils/JobManager.h373
1 files changed, 373 insertions, 0 deletions
diff --git a/xbmc/utils/JobManager.h b/xbmc/utils/JobManager.h
new file mode 100644
index 0000000..ac4aa4e
--- /dev/null
+++ b/xbmc/utils/JobManager.h
@@ -0,0 +1,373 @@
1/*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#pragma once
10
11#include "Job.h"
12#include "threads/CriticalSection.h"
13#include "threads/Thread.h"
14
15#include <queue>
16#include <string>
17#include <vector>
18
19class CJobManager;
20
21class CJobWorker : public CThread
22{
23public:
24 explicit CJobWorker(CJobManager *manager);
25 ~CJobWorker() override;
26
27 void Process() override;
28private:
29 CJobManager *m_jobManager;
30};
31
32template<typename F>
33class CLambdaJob : public CJob
34{
35public:
36 CLambdaJob(F&& f) : m_f(std::forward<F>(f)) {};
37 bool DoWork() override
38 {
39 m_f();
40 return true;
41 }
42 bool operator==(const CJob *job) const override
43 {
44 return this == job;
45 };
46private:
47 F m_f;
48};
49
50/*!
51 \ingroup jobs
52 \brief Job Queue class to handle a queue of unique jobs to be processed sequentially
53
54 Holds a queue of jobs to be processed sequentially, either first in,first out
55 or last in, first out. Jobs are unique, so queueing multiple copies of the same job
56 (based on the CJob::operator==) will not add additional jobs.
57
58 Classes should subclass this class and override OnJobCallback should they require
59 information from the job.
60
61 \sa CJob and IJobCallback
62 */
63class CJobQueue: public IJobCallback
64{
65 class CJobPointer
66 {
67 public:
68 explicit CJobPointer(CJob *job)
69 {
70 m_job = job;
71 m_id = 0;
72 };
73 void CancelJob();
74 void FreeJob()
75 {
76 delete m_job;
77 m_job = NULL;
78 };
79 bool operator==(const CJob *job) const
80 {
81 if (m_job)
82 return *m_job == job;
83 return false;
84 };
85 CJob *m_job;
86 unsigned int m_id;
87 };
88public:
89 /*!
90 \brief CJobQueue constructor
91 \param lifo whether the queue should be processed last in first out or first in first out. Defaults to false (first in first out)
92 \param jobsAtOnce number of jobs at once to process. Defaults to 1.
93 \param priority priority of this queue.
94 \sa CJob
95 */
96 CJobQueue(bool lifo = false, unsigned int jobsAtOnce = 1, CJob::PRIORITY priority = CJob::PRIORITY_LOW);
97
98 /*!
99 \brief CJobQueue destructor
100 Cancels any in-process jobs, and destroys the job queue.
101 \sa CJob
102 */
103 ~CJobQueue() override;
104
105 /*!
106 \brief Add a job to the queue
107 On completion of the job (or destruction of the job queue) the CJob object will be destroyed.
108 \param job a pointer to the job to add. The job should be subclassed from CJob.
109 \sa CJob
110 */
111 bool AddJob(CJob *job);
112
113 /*!
114 \brief Add a function f to this job queue
115 */
116 template<typename F>
117 void Submit(F&& f)
118 {
119 AddJob(new CLambdaJob<F>(std::forward<F>(f)));
120 }
121
122 /*!
123 \brief Cancel a job in the queue
124 Cancels a job in the queue. Any job currently being processed may complete after this
125 call has completed, but OnJobComplete will not be performed. If the job is only queued
126 then it will be removed from the queue and deleted.
127 \param job a pointer to the job to cancel. The job should be subclassed from CJob.
128 \sa CJob
129 */
130 void CancelJob(const CJob *job);
131
132 /*!
133 \brief Cancel all jobs in the queue
134 Removes all jobs from the queue. Any job currently being processed may complete after this
135 call has completed, but OnJobComplete will not be performed.
136 \sa CJob
137 */
138 void CancelJobs();
139
140 /*!
141 \brief Check whether the queue is processing a job
142 */
143 bool IsProcessing() const;
144
145 /*!
146 \brief The callback used when a job completes.
147
148 OnJobComplete is called at the completion of the CJob::DoWork function, and is used
149 to return information to the caller on the result of the job. On returning from this function
150 the CJobManager will destroy this job.
151
152 Subclasses should override this function if they wish to transfer information from the job prior
153 to it's deletion. They must then call this base class function, which will move on to the next
154 job.
155
156 \sa CJobManager, IJobCallback and CJob
157 */
158 void OnJobComplete(unsigned int jobID, bool success, CJob *job) override;
159
160protected:
161 /*!
162 \brief Returns if we still have jobs waiting to be processed
163 NOTE: This function does not take into account the jobs that are currently processing
164 */
165 bool QueueEmpty() const;
166
167private:
168 void QueueNextJob();
169
170 typedef std::deque<CJobPointer> Queue;
171 typedef std::vector<CJobPointer> Processing;
172 Queue m_jobQueue;
173 Processing m_processing;
174
175 unsigned int m_jobsAtOnce;
176 CJob::PRIORITY m_priority;
177 mutable CCriticalSection m_section;
178 bool m_lifo;
179};
180
181/*!
182 \ingroup jobs
183 \brief Job Manager class for scheduling asynchronous jobs.
184
185 Controls asynchronous job execution, by allowing clients to add and cancel jobs.
186 Should be accessed via CJobManager::GetInstance(). Jobs are allocated based on
187 priority levels. Lower priority jobs are executed only if there are sufficient
188 spare worker threads free to allow for higher priority jobs that may arise.
189
190 \sa CJob and IJobCallback
191 */
192class CJobManager final
193{
194 class CWorkItem
195 {
196 public:
197 CWorkItem(CJob *job, unsigned int id, CJob::PRIORITY priority, IJobCallback *callback)
198 {
199 m_job = job;
200 m_id = id;
201 m_callback = callback;
202 m_priority = priority;
203 }
204 bool operator==(unsigned int jobID) const
205 {
206 return m_id == jobID;
207 };
208 bool operator==(const CJob *job) const
209 {
210 return m_job == job;
211 };
212 void FreeJob()
213 {
214 delete m_job;
215 m_job = NULL;
216 };
217 void Cancel()
218 {
219 m_callback = NULL;
220 };
221 CJob *m_job;
222 unsigned int m_id;
223 IJobCallback *m_callback;
224 CJob::PRIORITY m_priority;
225 };
226
227public:
228 /*!
229 \brief The only way through which the global instance of the CJobManager should be accessed.
230 \return the global instance.
231 */
232 static CJobManager &GetInstance();
233
234 /*!
235 \brief Add a job to the threaded job manager.
236 \param job a pointer to the job to add. The job should be subclassed from CJob
237 \param callback a pointer to an IJobCallback instance to receive job progress and completion notices.
238 \param priority the priority that this job should run at.
239 \return a unique identifier for this job, to be used with other interaction
240 \sa CJob, IJobCallback, CancelJob()
241 */
242 unsigned int AddJob(CJob *job, IJobCallback *callback, CJob::PRIORITY priority = CJob::PRIORITY_LOW);
243
244 /*!
245 \brief Add a function f to this job manager for asynchronously execution.
246 */
247 template<typename F>
248 void Submit(F&& f, CJob::PRIORITY priority = CJob::PRIORITY_LOW)
249 {
250 AddJob(new CLambdaJob<F>(std::forward<F>(f)), nullptr, priority);
251 }
252
253 /*!
254 \brief Add a function f to this job manager for asynchronously execution.
255 */
256 template<typename F>
257 void Submit(F&& f, IJobCallback *callback, CJob::PRIORITY priority = CJob::PRIORITY_LOW)
258 {
259 AddJob(new CLambdaJob<F>(std::forward<F>(f)), callback, priority);
260 }
261
262 /*!
263 \brief Cancel a job with the given id.
264 \param jobID the id of the job to cancel, retrieved previously from AddJob()
265 \sa AddJob()
266 */
267 void CancelJob(unsigned int jobID);
268
269 /*!
270 \brief Cancel all remaining jobs, preparing for shutdown
271 Should be called prior to destroying any objects that may be being used as callbacks
272 \sa CancelJob(), AddJob()
273 */
274 void CancelJobs();
275
276 /*!
277 \brief Re-start accepting jobs again
278 Called after calling CancelJobs() to allow this manager to accept more jobs
279 \throws std::logic_error if the manager was not previously cancelled
280 \sa CancelJobs()
281 */
282 void Restart();
283
284 /*!
285 \brief Checks to see if any jobs of a specific type are currently processing.
286 \param type Job type to search for
287 \return Number of matching jobs
288 */
289 int IsProcessing(const std::string &type) const;
290
291 /*!
292 \brief Suspends queueing of jobs with priority PRIORITY_LOW_PAUSABLE until unpaused
293 Useful to (for ex) stop queuing thumb jobs during video start/playback.
294 Does not affect currently processing jobs, use IsProcessing to see if any need to be waited on
295 \sa UnPauseJobs()
296 */
297 void PauseJobs();
298
299 /*!
300 \brief Resumes queueing of (previously paused) jobs with priority PRIORITY_LOW_PAUSABLE
301 \sa PauseJobs()
302 */
303 void UnPauseJobs();
304
305 /*!
306 \brief Checks to see if any jobs with specific priority are currently processing.
307 \param priority to search for
308 \return true if processing jobs, else returns false
309 */
310 bool IsProcessing(const CJob::PRIORITY &priority) const;
311
312protected:
313 friend class CJobWorker;
314 friend class CJob;
315 friend class CJobQueue;
316
317 /*!
318 \brief Get a new job to process. Blocks until a new job is available, or a timeout has occurred.
319 \param worker a pointer to the current CJobWorker instance requesting a job.
320 \sa CJob
321 */
322 CJob *GetNextJob(const CJobWorker *worker);
323
324 /*!
325 \brief Callback from CJobWorker after a job has completed.
326 Calls IJobCallback::OnJobComplete(), and then destroys job.
327 \param job a pointer to the calling subclassed CJob instance.
328 \param success the result from the DoWork call
329 \sa IJobCallback, CJob
330 */
331 void OnJobComplete(bool success, CJob *job);
332
333 /*!
334 \brief Callback from CJob to report progress and check for cancellation.
335 Checks for cancellation, and calls IJobCallback::OnJobProgress().
336 \param progress amount of processing performed to date, out of total.
337 \param total total amount of processing.
338 \param job pointer to the calling subclassed CJob instance.
339 \return true if the job has been cancelled, else returns false.
340 \sa IJobCallback, CJob
341 */
342 bool OnJobProgress(unsigned int progress, unsigned int total, const CJob *job) const;
343
344private:
345 // private construction, and no assignments; use the provided singleton methods
346 CJobManager();
347 CJobManager(const CJobManager&) = delete;
348 CJobManager const& operator=(CJobManager const&) = delete;
349
350 /*! \brief Pop a job off the job queue and add to the processing queue ready to process
351 \return the job to process, NULL if no jobs are available
352 */
353 CJob *PopJob();
354
355 void StartWorkers(CJob::PRIORITY priority);
356 void RemoveWorker(const CJobWorker *worker);
357 static unsigned int GetMaxWorkers(CJob::PRIORITY priority);
358
359 unsigned int m_jobCounter;
360
361 typedef std::deque<CWorkItem> JobQueue;
362 typedef std::vector<CWorkItem> Processing;
363 typedef std::vector<CJobWorker*> Workers;
364
365 JobQueue m_jobQueue[CJob::PRIORITY_DEDICATED + 1];
366 bool m_pauseJobs;
367 Processing m_processing;
368 Workers m_workers;
369
370 mutable CCriticalSection m_section;
371 CEvent m_jobEvent;
372 bool m_running;
373};