ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / util / util_task.h
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __UTIL_TASK_H__
18 #define __UTIL_TASK_H__
19
20 #include "util/util_list.h"
21 #include "util/util_string.h"
22 #include "util/util_thread.h"
23 #include "util/util_vector.h"
24
25 CCL_NAMESPACE_BEGIN
26
27 class Task;
28 class TaskPool;
29 class TaskScheduler;
30
31 /* Notes on Thread ID
32  *
33  * Thread ID argument reports the 0-based ID of a working thread from which
34  * the run() callback is being invoked. Thread ID of 0 denotes the thread from
35  * which wait_work() was called.
36  *
37  * DO NOT use this ID to control execution flaw, use it only for things like
38  * emulating TLS which does not affect on scheduling. Don't use this ID to make
39  * any decisions.
40  *
41  * It is to be noted here that dedicated task pool will always report thread ID
42  * of 0.
43  */
44
45 typedef function<void(int thread_id)> TaskRunFunction;
46
47 /* Task
48  *
49  * Base class for tasks to be executed in threads. */
50
51 class Task {
52  public:
53   Task(){};
54   explicit Task(const TaskRunFunction &run_) : run(run_)
55   {
56   }
57
58   virtual ~Task()
59   {
60   }
61
62   TaskRunFunction run;
63 };
64
65 /* Task Pool
66  *
67  * Pool of tasks that will be executed by the central TaskScheduler.For each
68  * pool, we can wait for all tasks to be done, or cancel them before they are
69  * done.
70  *
71  * The run callback that actually executes the task may be created like this:
72  * function_bind(&MyClass::task_execute, this, _1, _2) */
73
74 class TaskPool {
75  public:
76   struct Summary {
77     /* Time spent to handle all tasks. */
78     double time_total;
79
80     /* Number of all tasks handled by this pool. */
81     int num_tasks_handled;
82
83     /* A full multiline description of the state of the pool after
84      * all work is done.
85      */
86     string full_report() const;
87   };
88
89   TaskPool();
90   ~TaskPool();
91
92   void push(Task *task, bool front = false);
93   void push(const TaskRunFunction &run, bool front = false);
94
95   void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
96   void cancel();                         /* cancel all tasks, keep worker threads running */
97   void stop();                           /* stop all worker threads */
98   bool finished();                       /* check if all work has been completed */
99
100   bool canceled(); /* for worker threads, test if canceled */
101
102  protected:
103   friend class TaskScheduler;
104
105   void num_decrease(int done);
106   void num_increase();
107
108   thread_mutex num_mutex;
109   thread_condition_variable num_cond;
110
111   int num;
112   bool do_cancel;
113
114   /* ** Statistics ** */
115
116   /* Time time stamp of first task pushed. */
117   double start_time;
118
119   /* Number of all tasks handled by this pool. */
120   int num_tasks_handled;
121 };
122
123 /* Task Scheduler
124  *
125  * Central scheduler that holds running threads ready to execute tasks. A singe
126  * queue holds the task from all pools. */
127
128 class TaskScheduler {
129  public:
130   static void init(int num_threads = 0);
131   static void exit();
132   static void free_memory();
133
134   /* number of threads that can work on task */
135   static int num_threads()
136   {
137     return threads.size();
138   }
139
140   /* test if any session is using the scheduler */
141   static bool active()
142   {
143     return users != 0;
144   }
145
146  protected:
147   friend class TaskPool;
148
149   struct Entry {
150     Task *task;
151     TaskPool *pool;
152   };
153
154   static thread_mutex mutex;
155   static int users;
156   static vector<thread *> threads;
157   static bool do_exit;
158
159   static list<Entry> queue;
160   static thread_mutex queue_mutex;
161   static thread_condition_variable queue_cond;
162
163   static void thread_run(int thread_id);
164   static bool thread_wait_pop(Entry &entry);
165
166   static void push(Entry &entry, bool front);
167   static void clear(TaskPool *pool);
168 };
169
170 /* Dedicated Task Pool
171  *
172  * Like a TaskPool, but will launch one dedicated thread to execute all tasks.
173  *
174  * The run callback that actually executes the task may be created like this:
175  * function_bind(&MyClass::task_execute, this, _1, _2) */
176
177 class DedicatedTaskPool {
178  public:
179   DedicatedTaskPool();
180   ~DedicatedTaskPool();
181
182   void push(Task *task, bool front = false);
183   void push(const TaskRunFunction &run, bool front = false);
184
185   void wait();   /* wait until all tasks are done */
186   void cancel(); /* cancel all tasks, keep worker thread running */
187   void stop();   /* stop worker thread */
188
189   bool canceled(); /* for worker thread, test if canceled */
190
191  protected:
192   void num_decrease(int done);
193   void num_increase();
194
195   void thread_run();
196   bool thread_wait_pop(Task *&entry);
197
198   void clear();
199
200   thread_mutex num_mutex;
201   thread_condition_variable num_cond;
202
203   list<Task *> queue;
204   thread_mutex queue_mutex;
205   thread_condition_variable queue_cond;
206
207   int num;
208   bool do_cancel;
209   bool do_exit;
210
211   thread *worker_thread;
212 };
213
214 CCL_NAMESPACE_END
215
216 #endif