5f957829e243e1df89196b53f9bdb2d6ddc74545
1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
4 * Authors: Steve Borho <steve@borho.org>
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.
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.
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.
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com
22 *****************************************************************************/
24 #ifndef X265_THREADING_H
25 #define X265_THREADING_H
32 #include "winxp.h" // XP workarounds for CONDITION_VARIABLE and ATOMIC_OR
35 #include <semaphore.h>
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
45 #ifdef __GNUC__ /* GCCs builtin atomics */
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)
58 #elif defined(_MSC_VER) /* Windows atomic intrinsics */
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)
70 #endif // ifdef __GNUC__
73 // x265 private namespace
77 typedef HANDLE ThreadHandle
;
85 InitializeCriticalSection(&this->handle
);
90 DeleteCriticalSection(&this->handle
);
95 EnterCriticalSection(&this->handle
);
100 LeaveCriticalSection(&this->handle
);
105 CRITICAL_SECTION handle
;
114 this->handle
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
119 CloseHandle(this->handle
);
124 WaitForSingleObject(this->handle
, INFINITE
);
127 bool timedWait(uint32_t milliseconds
)
129 /* returns true if event was signaled */
130 return WaitForSingleObject(this->handle
, milliseconds
) == WAIT_OBJECT_0
;
135 SetEvent(this->handle
);
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 */
148 class ThreadSafeInteger
155 InitializeCriticalSection(&m_cs
);
156 InitializeConditionVariable(&m_cv
);
161 DeleteCriticalSection(&m_cs
);
162 XP_CONDITION_VAR_FREE(&m_cv
);
165 int waitForChange(int prev
)
167 EnterCriticalSection(&m_cs
);
169 SleepConditionVariableCS(&m_cv
, &m_cs
, INFINITE
);
170 LeaveCriticalSection(&m_cs
);
176 EnterCriticalSection(&m_cs
);
178 LeaveCriticalSection(&m_cs
);
184 EnterCriticalSection(&m_cs
);
186 WakeAllConditionVariable(&m_cv
);
187 LeaveCriticalSection(&m_cs
);
192 EnterCriticalSection(&m_cs
);
194 WakeAllConditionVariable(&m_cv
);
195 LeaveCriticalSection(&m_cs
);
200 CRITICAL_SECTION m_cs
;
201 CONDITION_VARIABLE m_cv
;
205 #else /* POSIX / pthreads */
207 typedef pthread_t ThreadHandle
;
215 pthread_mutex_init(&this->handle
, NULL
);
220 pthread_mutex_destroy(&this->handle
);
225 pthread_mutex_lock(&this->handle
);
230 pthread_mutex_unlock(&this->handle
);
235 pthread_mutex_t handle
;
245 if (pthread_mutex_init(&m_mutex
, NULL
) ||
246 pthread_cond_init(&m_cond
, NULL
))
248 x265_log(NULL
, X265_LOG_ERROR
, "fatal: unable to initialize conditional variable\n");
254 pthread_cond_destroy(&m_cond
);
255 pthread_mutex_destroy(&m_mutex
);
260 pthread_mutex_lock(&m_mutex
);
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)
266 pthread_cond_wait(&m_cond
, &m_mutex
);
270 pthread_mutex_unlock(&m_mutex
);
273 bool timedWait(uint32_t waitms
)
275 bool bTimedOut
= false;
277 pthread_mutex_lock(&m_mutex
);
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;
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 */
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
;
299 pthread_mutex_unlock(&m_mutex
);
305 pthread_mutex_lock(&m_mutex
);
306 if (m_counter
< UINT_MAX
)
308 /* Signal a single blocking thread */
309 pthread_cond_signal(&m_cond
);
310 pthread_mutex_unlock(&m_mutex
);
315 pthread_mutex_t m_mutex
;
316 pthread_cond_t m_cond
;
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 */
325 class ThreadSafeInteger
332 if (pthread_mutex_init(&m_mutex
, NULL
) ||
333 pthread_cond_init(&m_cond
, NULL
))
335 x265_log(NULL
, X265_LOG_ERROR
, "fatal: unable to initialize conditional variable\n");
341 pthread_cond_destroy(&m_cond
);
342 pthread_mutex_destroy(&m_mutex
);
345 int waitForChange(int prev
)
347 pthread_mutex_lock(&m_mutex
);
349 pthread_cond_wait(&m_cond
, &m_mutex
);
350 pthread_mutex_unlock(&m_mutex
);
356 pthread_mutex_lock(&m_mutex
);
358 pthread_mutex_unlock(&m_mutex
);
364 pthread_mutex_lock(&m_mutex
);
366 pthread_cond_broadcast(&m_cond
);
367 pthread_mutex_unlock(&m_mutex
);
372 pthread_mutex_lock(&m_mutex
);
374 pthread_cond_broadcast(&m_cond
);
375 pthread_mutex_unlock(&m_mutex
);
380 pthread_mutex_t m_mutex
;
381 pthread_cond_t m_cond
;
385 #endif // ifdef _WIN32
391 ScopedLock(Lock
&instance
) : inst(instance
)
393 this->inst
.acquire();
398 this->inst
.release();
403 // do not allow assignments
404 ScopedLock
&operator =(const ScopedLock
&);
409 //< Simplistic portable thread class. Shutdown signalling left to derived class
422 //< Derived class must implement ThreadMain.
423 virtual void threadMain() = 0;
425 //< Returns true if thread was successfully created
430 } // end namespace x265
432 #endif // ifndef X265_THREADING_H