1 /*****************************************************************************
2 * x265: threading class and intrinsics
3 *****************************************************************************
4 * Copyright (C) 2013 x265 project
6 * Authors: Steve Borho <steve@borho.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 * This program is also available under a commercial proprietary license.
23 * For more information, contact us at license @ x265.com
24 *****************************************************************************/
26 #ifndef X265_THREADING_H
27 #define X265_THREADING_H
34 #include "winxp.h" // XP workarounds for CONDITION_VARIABLE and ATOMIC_OR
37 #include <semaphore.h>
43 #include <sys/param.h>
44 #include <sys/sysctl.h>
47 #ifdef __GNUC__ /* GCCs builtin atomics */
52 #define CLZ32(id, x) id = (unsigned long)__builtin_clz(x) ^ 31
53 #define CTZ64(id, x) id = (unsigned long)__builtin_ctzll(x)
54 #define ATOMIC_OR(ptr, mask) __sync_or_and_fetch(ptr, mask)
55 #define ATOMIC_CAS(ptr, oldval, newval) __sync_val_compare_and_swap(ptr, oldval, newval)
56 #define ATOMIC_CAS32(ptr, oldval, newval) __sync_val_compare_and_swap(ptr, oldval, newval)
57 #define ATOMIC_INC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, 1)
58 #define ATOMIC_DEC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, -1)
59 #define GIVE_UP_TIME() usleep(0)
61 #elif defined(_MSC_VER) /* Windows atomic intrinsics */
66 inline int _BitScanReverse64(DWORD
*id
, uint64_t x64
) // fake 64bit CLZ
68 uint32_t high32
= (uint32_t)(x64
>> 32);
69 uint32_t low32
= (uint32_t)x64
;
73 _BitScanReverse(id
, high32
);
78 return _BitScanReverse(id
, low32
);
83 inline int _BitScanForward64(DWORD
*id
, uint64_t x64
) // fake 64bit CLZ
85 uint32_t high32
= (uint32_t)(x64
>> 32);
86 uint32_t low32
= (uint32_t)x64
;
90 _BitScanForward(id
, high32
);
95 return _BitScanForward(id
, low32
);
103 #define ATOMIC_OR(ptr, mask) InterlockedOr64((volatile LONG64*)ptr, mask)
106 #define CLZ32(id, x) _BitScanReverse(&id, x)
107 #define CTZ64(id, x) _BitScanForward64(&id, x)
108 #define ATOMIC_CAS(ptr, oldval, newval) (uint64_t)_InterlockedCompareExchange64((volatile LONG64*)ptr, newval, oldval)
109 #define ATOMIC_CAS32(ptr, oldval, newval) (uint64_t)_InterlockedCompareExchange((volatile LONG*)ptr, newval, oldval)
110 #define ATOMIC_INC(ptr) InterlockedIncrement((volatile LONG*)ptr)
111 #define ATOMIC_DEC(ptr) InterlockedDecrement((volatile LONG*)ptr)
112 #define GIVE_UP_TIME() Sleep(0)
114 #endif // ifdef __GNUC__
117 // x265 private namespace
121 typedef HANDLE ThreadHandle
;
129 InitializeCriticalSection(&this->handle
);
134 DeleteCriticalSection(&this->handle
);
139 EnterCriticalSection(&this->handle
);
144 LeaveCriticalSection(&this->handle
);
149 CRITICAL_SECTION handle
;
158 this->handle
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
163 CloseHandle(this->handle
);
168 WaitForSingleObject(this->handle
, INFINITE
);
171 bool timedWait(uint32_t milliseconds
)
173 /* returns true if event was signaled */
174 return WaitForSingleObject(this->handle
, milliseconds
) == WAIT_OBJECT_0
;
179 SetEvent(this->handle
);
187 /* This class is intended for use in signaling state changes safely between CPU
188 * cores. One thread should be a writer and multiple threads may be readers. The
189 * mutex's main purpose is to serve as a memory fence to ensure writes made by
190 * the writer thread are visible prior to readers seeing the m_val change. Its
191 * secondary purpose is for use with the condition variable for blocking waits */
192 class ThreadSafeInteger
199 InitializeCriticalSection(&m_cs
);
200 InitializeConditionVariable(&m_cv
);
205 DeleteCriticalSection(&m_cs
);
206 XP_CONDITION_VAR_FREE(&m_cv
);
209 int waitForChange(int prev
)
211 EnterCriticalSection(&m_cs
);
213 SleepConditionVariableCS(&m_cv
, &m_cs
, INFINITE
);
214 LeaveCriticalSection(&m_cs
);
220 EnterCriticalSection(&m_cs
);
222 LeaveCriticalSection(&m_cs
);
228 EnterCriticalSection(&m_cs
);
230 WakeAllConditionVariable(&m_cv
);
231 LeaveCriticalSection(&m_cs
);
236 EnterCriticalSection(&m_cs
);
238 WakeAllConditionVariable(&m_cv
);
239 LeaveCriticalSection(&m_cs
);
244 CRITICAL_SECTION m_cs
;
245 CONDITION_VARIABLE m_cv
;
249 #else /* POSIX / pthreads */
251 typedef pthread_t ThreadHandle
;
259 pthread_mutex_init(&this->handle
, NULL
);
264 pthread_mutex_destroy(&this->handle
);
269 pthread_mutex_lock(&this->handle
);
274 pthread_mutex_unlock(&this->handle
);
279 pthread_mutex_t handle
;
289 if (pthread_mutex_init(&m_mutex
, NULL
) ||
290 pthread_cond_init(&m_cond
, NULL
))
292 x265_log(NULL
, X265_LOG_ERROR
, "fatal: unable to initialize conditional variable\n");
298 pthread_cond_destroy(&m_cond
);
299 pthread_mutex_destroy(&m_mutex
);
304 pthread_mutex_lock(&m_mutex
);
306 /* blocking wait on conditional variable, mutex is atomically released
307 * while blocked. When condition is signaled, mutex is re-acquired */
308 while (m_counter
== 0)
310 pthread_cond_wait(&m_cond
, &m_mutex
);
314 pthread_mutex_unlock(&m_mutex
);
317 bool timedWait(uint32_t waitms
)
319 bool bTimedOut
= false;
321 pthread_mutex_lock(&m_mutex
);
326 gettimeofday(&tv
, NULL
);
327 /* convert current time from (sec, usec) to (sec, nsec) */
328 ts
.tv_sec
= tv
.tv_sec
;
329 ts
.tv_nsec
= tv
.tv_usec
* 1000;
331 ts
.tv_nsec
+= 1000 * 1000 * (waitms
% 1000); /* add ms to tv_nsec */
332 ts
.tv_sec
+= ts
.tv_nsec
/ (1000 * 1000 * 1000); /* overflow tv_nsec */
333 ts
.tv_nsec
%= (1000 * 1000 * 1000); /* clamp tv_nsec */
334 ts
.tv_sec
+= waitms
/ 1000; /* add seconds */
336 /* blocking wait on conditional variable, mutex is atomically released
337 * while blocked. When condition is signaled, mutex is re-acquired.
338 * ts is absolute time to stop waiting */
339 bTimedOut
= pthread_cond_timedwait(&m_cond
, &m_mutex
, &ts
) == ETIMEDOUT
;
343 pthread_mutex_unlock(&m_mutex
);
349 pthread_mutex_lock(&m_mutex
);
350 if (m_counter
< UINT_MAX
)
352 /* Signal a single blocking thread */
353 pthread_cond_signal(&m_cond
);
354 pthread_mutex_unlock(&m_mutex
);
359 pthread_mutex_t m_mutex
;
360 pthread_cond_t m_cond
;
364 /* This class is intended for use in signaling state changes safely between CPU
365 * cores. One thread should be a writer and multiple threads may be readers. The
366 * mutex's main purpose is to serve as a memory fence to ensure writes made by
367 * the writer thread are visible prior to readers seeing the m_val change. Its
368 * secondary purpose is for use with the condition variable for blocking waits */
369 class ThreadSafeInteger
376 if (pthread_mutex_init(&m_mutex
, NULL
) ||
377 pthread_cond_init(&m_cond
, NULL
))
379 x265_log(NULL
, X265_LOG_ERROR
, "fatal: unable to initialize conditional variable\n");
385 pthread_cond_destroy(&m_cond
);
386 pthread_mutex_destroy(&m_mutex
);
389 int waitForChange(int prev
)
391 pthread_mutex_lock(&m_mutex
);
393 pthread_cond_wait(&m_cond
, &m_mutex
);
394 pthread_mutex_unlock(&m_mutex
);
400 pthread_mutex_lock(&m_mutex
);
402 pthread_mutex_unlock(&m_mutex
);
408 pthread_mutex_lock(&m_mutex
);
410 pthread_cond_broadcast(&m_cond
);
411 pthread_mutex_unlock(&m_mutex
);
416 pthread_mutex_lock(&m_mutex
);
418 pthread_cond_broadcast(&m_cond
);
419 pthread_mutex_unlock(&m_mutex
);
424 pthread_mutex_t m_mutex
;
425 pthread_cond_t m_cond
;
429 #endif // ifdef _WIN32
435 ScopedLock(Lock
&instance
) : inst(instance
)
437 this->inst
.acquire();
442 this->inst
.release();
447 // do not allow assignments
448 ScopedLock
&operator =(const ScopedLock
&);
453 //< Simplistic portable thread class. Shutdown signalling left to derived class
466 //< Derived class must implement ThreadMain.
467 virtual void threadMain() = 0;
469 //< Returns true if thread was successfully created
474 } // end namespace x265
476 #endif // ifndef X265_THREADING_H