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