Fix cut&paste typo in changelog.
[deb_x265.git] / source / common / threading.h
... / ...
CommitLineData
1/*****************************************************************************
2 * Copyright (C) 2013 x265 project
3 *
4 * Authors: Steve Borho <steve@borho.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
19 *
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com
22 *****************************************************************************/
23
24#ifndef X265_THREADING_H
25#define X265_THREADING_H
26
27#include "common.h"
28#include "x265.h"
29
30#ifdef _WIN32
31#include <windows.h>
32#include "winxp.h" // XP workarounds for CONDITION_VARIABLE and ATOMIC_OR
33#else
34#include <pthread.h>
35#include <semaphore.h>
36#include <errno.h>
37#include <fcntl.h>
38#endif
39
40#if MACOS
41#include <sys/param.h>
42#include <sys/sysctl.h>
43#endif
44
45#ifdef __GNUC__ /* GCCs builtin atomics */
46
47#include <sys/time.h>
48#include <unistd.h>
49
50#define CLZ(id, x) id = (unsigned long)__builtin_clz(x) ^ 31
51#define CTZ(id, x) id = (unsigned long)__builtin_ctz(x)
52#define ATOMIC_OR(ptr, mask) __sync_fetch_and_or(ptr, mask)
53#define ATOMIC_AND(ptr, mask) __sync_fetch_and_and(ptr, mask)
54#define ATOMIC_INC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, 1)
55#define ATOMIC_DEC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, -1)
56#define GIVE_UP_TIME() usleep(0)
57
58#elif defined(_MSC_VER) /* Windows atomic intrinsics */
59
60#include <intrin.h>
61
62#define CLZ(id, x) _BitScanReverse(&id, x)
63#define CTZ(id, x) _BitScanForward(&id, x)
64#define ATOMIC_INC(ptr) InterlockedIncrement((volatile LONG*)ptr)
65#define ATOMIC_DEC(ptr) InterlockedDecrement((volatile LONG*)ptr)
66#define ATOMIC_OR(ptr, mask) _InterlockedOr((volatile LONG*)ptr, (LONG)mask)
67#define ATOMIC_AND(ptr, mask) _InterlockedAnd((volatile LONG*)ptr, (LONG)mask)
68#define GIVE_UP_TIME() Sleep(0)
69
70#endif // ifdef __GNUC__
71
72namespace x265 {
73// x265 private namespace
74
75#ifdef _WIN32
76
77typedef HANDLE ThreadHandle;
78
79class Lock
80{
81public:
82
83 Lock()
84 {
85 InitializeCriticalSection(&this->handle);
86 }
87
88 ~Lock()
89 {
90 DeleteCriticalSection(&this->handle);
91 }
92
93 void acquire()
94 {
95 EnterCriticalSection(&this->handle);
96 }
97
98 void release()
99 {
100 LeaveCriticalSection(&this->handle);
101 }
102
103protected:
104
105 CRITICAL_SECTION handle;
106};
107
108class Event
109{
110public:
111
112 Event()
113 {
114 this->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
115 }
116
117 ~Event()
118 {
119 CloseHandle(this->handle);
120 }
121
122 void wait()
123 {
124 WaitForSingleObject(this->handle, INFINITE);
125 }
126
127 bool timedWait(uint32_t milliseconds)
128 {
129 /* returns true if event was signaled */
130 return WaitForSingleObject(this->handle, milliseconds) == WAIT_OBJECT_0;
131 }
132
133 void trigger()
134 {
135 SetEvent(this->handle);
136 }
137
138protected:
139
140 HANDLE handle;
141};
142
143/* This class is intended for use in signaling state changes safely between CPU
144 * cores. One thread should be a writer and multiple threads may be readers. The
145 * mutex's main purpose is to serve as a memory fence to ensure writes made by
146 * the writer thread are visible prior to readers seeing the m_val change. Its
147 * secondary purpose is for use with the condition variable for blocking waits */
148class ThreadSafeInteger
149{
150public:
151
152 ThreadSafeInteger()
153 {
154 m_val = 0;
155 InitializeCriticalSection(&m_cs);
156 InitializeConditionVariable(&m_cv);
157 }
158
159 ~ThreadSafeInteger()
160 {
161 DeleteCriticalSection(&m_cs);
162 XP_CONDITION_VAR_FREE(&m_cv);
163 }
164
165 int waitForChange(int prev)
166 {
167 EnterCriticalSection(&m_cs);
168 if (m_val == prev)
169 SleepConditionVariableCS(&m_cv, &m_cs, INFINITE);
170 LeaveCriticalSection(&m_cs);
171 return m_val;
172 }
173
174 int get()
175 {
176 EnterCriticalSection(&m_cs);
177 int ret = m_val;
178 LeaveCriticalSection(&m_cs);
179 return ret;
180 }
181
182 void set(int newval)
183 {
184 EnterCriticalSection(&m_cs);
185 m_val = newval;
186 WakeAllConditionVariable(&m_cv);
187 LeaveCriticalSection(&m_cs);
188 }
189
190 void incr()
191 {
192 EnterCriticalSection(&m_cs);
193 m_val++;
194 WakeAllConditionVariable(&m_cv);
195 LeaveCriticalSection(&m_cs);
196 }
197
198protected:
199
200 CRITICAL_SECTION m_cs;
201 CONDITION_VARIABLE m_cv;
202 int m_val;
203};
204
205#else /* POSIX / pthreads */
206
207typedef pthread_t ThreadHandle;
208
209class Lock
210{
211public:
212
213 Lock()
214 {
215 pthread_mutex_init(&this->handle, NULL);
216 }
217
218 ~Lock()
219 {
220 pthread_mutex_destroy(&this->handle);
221 }
222
223 void acquire()
224 {
225 pthread_mutex_lock(&this->handle);
226 }
227
228 void release()
229 {
230 pthread_mutex_unlock(&this->handle);
231 }
232
233protected:
234
235 pthread_mutex_t handle;
236};
237
238class Event
239{
240public:
241
242 Event()
243 {
244 m_counter = 0;
245 if (pthread_mutex_init(&m_mutex, NULL) ||
246 pthread_cond_init(&m_cond, NULL))
247 {
248 x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
249 }
250 }
251
252 ~Event()
253 {
254 pthread_cond_destroy(&m_cond);
255 pthread_mutex_destroy(&m_mutex);
256 }
257
258 void wait()
259 {
260 pthread_mutex_lock(&m_mutex);
261
262 /* blocking wait on conditional variable, mutex is atomically released
263 * while blocked. When condition is signaled, mutex is re-acquired */
264 while (m_counter == 0)
265 {
266 pthread_cond_wait(&m_cond, &m_mutex);
267 }
268
269 m_counter--;
270 pthread_mutex_unlock(&m_mutex);
271 }
272
273 bool timedWait(uint32_t waitms)
274 {
275 bool bTimedOut = false;
276
277 pthread_mutex_lock(&m_mutex);
278 if (m_counter == 0)
279 {
280 struct timeval tv;
281 struct timespec ts;
282 gettimeofday(&tv, NULL);
283 /* convert current time from (sec, usec) to (sec, nsec) */
284 ts.tv_sec = tv.tv_sec;
285 ts.tv_nsec = tv.tv_usec * 1000;
286
287 ts.tv_nsec += 1000 * 1000 * (waitms % 1000); /* add ms to tv_nsec */
288 ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000); /* overflow tv_nsec */
289 ts.tv_nsec %= (1000 * 1000 * 1000); /* clamp tv_nsec */
290 ts.tv_sec += waitms / 1000; /* add seconds */
291
292 /* blocking wait on conditional variable, mutex is atomically released
293 * while blocked. When condition is signaled, mutex is re-acquired.
294 * ts is absolute time to stop waiting */
295 bTimedOut = pthread_cond_timedwait(&m_cond, &m_mutex, &ts) == ETIMEDOUT;
296 }
297 if (m_counter > 0)
298 m_counter--;
299 pthread_mutex_unlock(&m_mutex);
300 return bTimedOut;
301 }
302
303 void trigger()
304 {
305 pthread_mutex_lock(&m_mutex);
306 if (m_counter < UINT_MAX)
307 m_counter++;
308 /* Signal a single blocking thread */
309 pthread_cond_signal(&m_cond);
310 pthread_mutex_unlock(&m_mutex);
311 }
312
313protected:
314
315 pthread_mutex_t m_mutex;
316 pthread_cond_t m_cond;
317 uint32_t m_counter;
318};
319
320/* This class is intended for use in signaling state changes safely between CPU
321 * cores. One thread should be a writer and multiple threads may be readers. The
322 * mutex's main purpose is to serve as a memory fence to ensure writes made by
323 * the writer thread are visible prior to readers seeing the m_val change. Its
324 * secondary purpose is for use with the condition variable for blocking waits */
325class ThreadSafeInteger
326{
327public:
328
329 ThreadSafeInteger()
330 {
331 m_val = 0;
332 if (pthread_mutex_init(&m_mutex, NULL) ||
333 pthread_cond_init(&m_cond, NULL))
334 {
335 x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
336 }
337 }
338
339 ~ThreadSafeInteger()
340 {
341 pthread_cond_destroy(&m_cond);
342 pthread_mutex_destroy(&m_mutex);
343 }
344
345 int waitForChange(int prev)
346 {
347 pthread_mutex_lock(&m_mutex);
348 if (m_val == prev)
349 pthread_cond_wait(&m_cond, &m_mutex);
350 pthread_mutex_unlock(&m_mutex);
351 return m_val;
352 }
353
354 int get()
355 {
356 pthread_mutex_lock(&m_mutex);
357 int ret = m_val;
358 pthread_mutex_unlock(&m_mutex);
359 return ret;
360 }
361
362 void set(int newval)
363 {
364 pthread_mutex_lock(&m_mutex);
365 m_val = newval;
366 pthread_cond_broadcast(&m_cond);
367 pthread_mutex_unlock(&m_mutex);
368 }
369
370 void incr()
371 {
372 pthread_mutex_lock(&m_mutex);
373 m_val++;
374 pthread_cond_broadcast(&m_cond);
375 pthread_mutex_unlock(&m_mutex);
376 }
377
378protected:
379
380 pthread_mutex_t m_mutex;
381 pthread_cond_t m_cond;
382 int m_val;
383};
384
385#endif // ifdef _WIN32
386
387class ScopedLock
388{
389public:
390
391 ScopedLock(Lock &instance) : inst(instance)
392 {
393 this->inst.acquire();
394 }
395
396 ~ScopedLock()
397 {
398 this->inst.release();
399 }
400
401protected:
402
403 // do not allow assignments
404 ScopedLock &operator =(const ScopedLock &);
405
406 Lock &inst;
407};
408
409//< Simplistic portable thread class. Shutdown signalling left to derived class
410class Thread
411{
412private:
413
414 ThreadHandle thread;
415
416public:
417
418 Thread();
419
420 virtual ~Thread();
421
422 //< Derived class must implement ThreadMain.
423 virtual void threadMain() = 0;
424
425 //< Returns true if thread was successfully created
426 bool start();
427
428 void stop();
429};
430} // end namespace x265
431
432#endif // ifndef X265_THREADING_H