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