Coverage Report

Created: 2025-07-23 08:18

/src/x265/source/common/threading.h
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * Copyright (C) 2013-2020 MulticoreWare, Inc
3
 *
4
 * Authors: Steve Borho <steve@borho.org>
5
 *          Min Chen <chenm003@163.com>
6
            liwei <liwei@multicorewareinc.com>
7
 *
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.
12
 *
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.
17
 *
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.
21
 *
22
 * This program is also available under a commercial proprietary license.
23
 * For more information, contact us at license @ x265.com
24
 *****************************************************************************/
25
26
#ifndef X265_THREADING_H
27
#define X265_THREADING_H
28
29
#include "common.h"
30
#include "x265.h"
31
32
#ifdef _WIN32
33
#include <windows.h>
34
#include "winxp.h"  // XP workarounds for CONDITION_VARIABLE and ATOMIC_OR
35
#else
36
#include <pthread.h>
37
#include <semaphore.h>
38
#include <errno.h>
39
#include <fcntl.h>
40
#endif
41
42
#if MACOS
43
#include <sys/param.h>
44
#include <sys/sysctl.h>
45
#endif
46
47
#if NO_ATOMICS
48
49
#include <sys/time.h>
50
#include <unistd.h>
51
52
namespace X265_NS {
53
// x265 private namespace
54
int no_atomic_or(int* ptr, int mask);
55
int no_atomic_and(int* ptr, int mask);
56
int no_atomic_inc(int* ptr);
57
int no_atomic_dec(int* ptr);
58
int no_atomic_add(int* ptr, int val);
59
}
60
61
#define BSR(id, x)            (id) = ((unsigned long)__builtin_clz(x) ^ 31)
62
#define BSF(id, x)            (id) = ((unsigned long)__builtin_ctz(x))
63
#define BSR64(id, x)          (id) = ((unsigned long)__builtin_clzll(x) ^ 63)
64
#define BSF64(id, x)          (id) = ((unsigned long)__builtin_ctzll(x))
65
#define ATOMIC_OR(ptr, mask)  no_atomic_or((int*)ptr, mask)
66
#define ATOMIC_AND(ptr, mask) no_atomic_and((int*)ptr, mask)
67
#define ATOMIC_INC(ptr)       no_atomic_inc((int*)ptr)
68
#define ATOMIC_DEC(ptr)       no_atomic_dec((int*)ptr)
69
#define ATOMIC_ADD(ptr, val)  no_atomic_add((int*)ptr, val)
70
#define GIVE_UP_TIME()        usleep(0)
71
72
#elif __GNUC__               /* GCCs builtin atomics */
73
74
#include <sys/time.h>
75
#include <unistd.h>
76
77
0
#define BSR(id, x)            (id) = ((unsigned long)__builtin_clz(x) ^ 31)
78
0
#define BSF(id, x)            (id) = ((unsigned long)__builtin_ctz(x))
79
#define BSR64(id, x)          (id) = ((unsigned long)__builtin_clzll(x) ^ 63)
80
#define BSF64(id, x)          (id) = ((unsigned long)__builtin_ctzll(x))
81
0
#define ATOMIC_OR(ptr, mask)  __sync_fetch_and_or(ptr, mask)
82
0
#define ATOMIC_AND(ptr, mask) __sync_fetch_and_and(ptr, mask)
83
0
#define ATOMIC_INC(ptr)       __sync_add_and_fetch((volatile int32_t*)ptr, 1)
84
0
#define ATOMIC_DEC(ptr)       __sync_add_and_fetch((volatile int32_t*)ptr, -1)
85
0
#define ATOMIC_ADD(ptr, val)  __sync_fetch_and_add((volatile int32_t*)ptr, val)
86
0
#define GIVE_UP_TIME()        usleep(0)
87
88
#elif defined(_MSC_VER)       /* Windows atomic intrinsics */
89
90
#include <intrin.h>
91
92
#define BSR(id, x)            _BitScanReverse(&id, x)
93
#define BSF(id, x)            _BitScanForward(&id, x)
94
#define BSR64(id, x)          _BitScanReverse64(&id, x)
95
#define BSF64(id, x)          _BitScanForward64(&id, x)
96
#define ATOMIC_INC(ptr)       InterlockedIncrement((volatile LONG*)ptr)
97
#define ATOMIC_DEC(ptr)       InterlockedDecrement((volatile LONG*)ptr)
98
#define ATOMIC_ADD(ptr, val)  InterlockedExchangeAdd((volatile LONG*)ptr, val)
99
#define ATOMIC_OR(ptr, mask)  _InterlockedOr((volatile LONG*)ptr, (LONG)mask)
100
#define ATOMIC_AND(ptr, mask) _InterlockedAnd((volatile LONG*)ptr, (LONG)mask)
101
#define GIVE_UP_TIME()        Sleep(0)
102
103
#endif // ifdef __GNUC__
104
105
namespace X265_NS {
106
// x265 private namespace
107
108
#ifdef _WIN32
109
110
typedef HANDLE ThreadHandle;
111
112
class Lock
113
{
114
public:
115
116
    Lock()
117
    {
118
        InitializeCriticalSection(&this->handle);
119
    }
120
121
    ~Lock()
122
    {
123
        DeleteCriticalSection(&this->handle);
124
    }
125
126
    void acquire()
127
    {
128
        EnterCriticalSection(&this->handle);
129
    }
130
131
    void release()
132
    {
133
        LeaveCriticalSection(&this->handle);
134
    }
135
136
protected:
137
138
    CRITICAL_SECTION handle;
139
};
140
141
class Event
142
{
143
public:
144
145
    Event()
146
    {
147
        this->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
148
    }
149
150
    ~Event()
151
    {
152
        CloseHandle(this->handle);
153
    }
154
155
    void wait()
156
    {
157
        WaitForSingleObject(this->handle, INFINITE);
158
    }
159
160
    bool timedWait(uint32_t milliseconds)
161
    {
162
        /* returns true if the wait timed out */
163
        return WaitForSingleObject(this->handle, milliseconds) == WAIT_TIMEOUT;
164
    }
165
166
    void trigger()
167
    {
168
        SetEvent(this->handle);
169
    }
170
171
protected:
172
173
    HANDLE handle;
174
};
175
176
/* This class is intended for use in signaling state changes safely between CPU
177
 * cores. One thread should be a writer and multiple threads may be readers. The
178
 * mutex's main purpose is to serve as a memory fence to ensure writes made by
179
 * the writer thread are visible prior to readers seeing the m_val change. Its
180
 * secondary purpose is for use with the condition variable for blocking waits */
181
class ThreadSafeInteger
182
{
183
public:
184
185
    ThreadSafeInteger()
186
    {
187
        m_val = 0;
188
        InitializeCriticalSection(&m_cs);
189
        InitializeConditionVariable(&m_cv);
190
    }
191
192
    ~ThreadSafeInteger()
193
    {
194
        DeleteCriticalSection(&m_cs);
195
        XP_CONDITION_VAR_FREE(&m_cv);
196
    }
197
198
    int waitForChange(int prev)
199
    {
200
        EnterCriticalSection(&m_cs);
201
        if (m_val == prev)
202
            SleepConditionVariableCS(&m_cv, &m_cs, INFINITE);
203
        LeaveCriticalSection(&m_cs);
204
        return m_val;
205
    }
206
207
    int get()
208
    {
209
        EnterCriticalSection(&m_cs);
210
        int ret = m_val;
211
        LeaveCriticalSection(&m_cs);
212
        return ret;
213
    }
214
215
    int getIncr(int n = 1)
216
    {
217
        EnterCriticalSection(&m_cs);
218
        int ret = m_val;
219
        m_val += n;
220
        LeaveCriticalSection(&m_cs);
221
        return ret;
222
    }
223
224
    void set(int newval)
225
    {
226
        EnterCriticalSection(&m_cs);
227
        m_val = newval;
228
        WakeAllConditionVariable(&m_cv);
229
        LeaveCriticalSection(&m_cs);
230
    }
231
232
    void poke(void)
233
    {
234
        /* awaken all waiting threads, but make no change */
235
        EnterCriticalSection(&m_cs);
236
        WakeAllConditionVariable(&m_cv);
237
        LeaveCriticalSection(&m_cs);
238
    }
239
240
    void incr()
241
    {
242
        EnterCriticalSection(&m_cs);
243
        m_val++;
244
        WakeAllConditionVariable(&m_cv);
245
        LeaveCriticalSection(&m_cs);
246
    }
247
248
    void decr()
249
    {
250
        EnterCriticalSection(&m_cs);
251
        m_val--;
252
        WakeAllConditionVariable(&m_cv);
253
        LeaveCriticalSection(&m_cs);
254
    }
255
256
protected:
257
258
    CRITICAL_SECTION   m_cs;
259
    CONDITION_VARIABLE m_cv;
260
    int                m_val;
261
};
262
263
class NamedSemaphore
264
{
265
public:
266
    NamedSemaphore() : m_sem(NULL)
267
    {
268
    }
269
270
    ~NamedSemaphore()
271
    {
272
    }
273
274
    bool create(const char* name, const int initcnt, const int maxcnt)
275
    {
276
        if(!m_sem)
277
        {
278
            m_sem = CreateSemaphoreA(NULL, initcnt, maxcnt, name);
279
        }
280
        return m_sem != NULL;
281
    }
282
283
    bool give(const int32_t cnt)
284
    {
285
        return ReleaseSemaphore(m_sem, (LONG)cnt, NULL) != FALSE;
286
    }
287
288
    bool take(const uint32_t time_out = INFINITE)
289
    {
290
        int32_t rt = WaitForSingleObject(m_sem, time_out);
291
        return rt != WAIT_TIMEOUT && rt != WAIT_FAILED;
292
    }
293
294
    void release()
295
    {
296
        CloseHandle(m_sem);
297
        m_sem = NULL;
298
    }
299
300
private:
301
    HANDLE m_sem;
302
};
303
304
#else /* POSIX / pthreads */
305
306
typedef pthread_t ThreadHandle;
307
308
class Lock
309
{
310
public:
311
312
    Lock()
313
0
    {
314
0
        pthread_mutex_init(&this->handle, NULL);
315
0
    }
316
317
    ~Lock()
318
0
    {
319
0
        pthread_mutex_destroy(&this->handle);
320
0
    }
321
322
    void acquire()
323
0
    {
324
0
        pthread_mutex_lock(&this->handle);
325
0
    }
326
327
    void release()
328
0
    {
329
0
        pthread_mutex_unlock(&this->handle);
330
0
    }
331
332
protected:
333
334
    pthread_mutex_t handle;
335
};
336
337
class Event
338
{
339
public:
340
341
    Event()
342
0
    {
343
0
        m_counter = 0;
344
0
        if (pthread_mutex_init(&m_mutex, NULL) ||
345
0
            pthread_cond_init(&m_cond, NULL))
346
0
        {
347
0
            x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
348
0
        }
349
0
    }
350
351
    ~Event()
352
0
    {
353
0
        pthread_cond_destroy(&m_cond);
354
0
        pthread_mutex_destroy(&m_mutex);
355
0
    }
356
357
    void wait()
358
0
    {
359
0
        pthread_mutex_lock(&m_mutex);
360
361
        /* blocking wait on conditional variable, mutex is atomically released
362
         * while blocked. When condition is signaled, mutex is re-acquired */
363
0
        while (!m_counter)
364
0
            pthread_cond_wait(&m_cond, &m_mutex);
365
366
0
        m_counter--;
367
0
        pthread_mutex_unlock(&m_mutex);
368
0
    }
369
370
    bool timedWait(uint32_t waitms)
371
0
    {
372
0
        bool bTimedOut = false;
373
374
0
        pthread_mutex_lock(&m_mutex);
375
0
        if (!m_counter)
376
0
        {
377
0
            struct timeval tv;
378
0
            struct timespec ts;
379
0
            gettimeofday(&tv, NULL);
380
            /* convert current time from (sec, usec) to (sec, nsec) */
381
0
            ts.tv_sec = tv.tv_sec;
382
0
            ts.tv_nsec = tv.tv_usec * 1000;
383
384
0
            ts.tv_nsec += 1000 * 1000 * (waitms % 1000);    /* add ms to tv_nsec */
385
0
            ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000); /* overflow tv_nsec */
386
0
            ts.tv_nsec %= (1000 * 1000 * 1000);             /* clamp tv_nsec */
387
0
            ts.tv_sec += waitms / 1000;                     /* add seconds */
388
389
            /* blocking wait on conditional variable, mutex is atomically released
390
             * while blocked. When condition is signaled, mutex is re-acquired.
391
             * ts is absolute time to stop waiting */
392
0
            bTimedOut = pthread_cond_timedwait(&m_cond, &m_mutex, &ts) == ETIMEDOUT;
393
0
        }
394
0
        if (m_counter > 0)
395
0
        {
396
0
            m_counter--;
397
0
            bTimedOut = false;
398
0
        }
399
0
        pthread_mutex_unlock(&m_mutex);
400
0
        return bTimedOut;
401
0
    }
402
403
    void trigger()
404
0
    {
405
0
        pthread_mutex_lock(&m_mutex);
406
0
        if (m_counter < UINT_MAX)
407
0
            m_counter++;
408
        /* Signal a single blocking thread */
409
0
        pthread_cond_signal(&m_cond);
410
0
        pthread_mutex_unlock(&m_mutex);
411
0
    }
412
413
protected:
414
415
    pthread_mutex_t m_mutex;
416
    pthread_cond_t  m_cond;
417
    uint32_t        m_counter;
418
};
419
420
/* This class is intended for use in signaling state changes safely between CPU
421
 * cores. One thread should be a writer and multiple threads may be readers. The
422
 * mutex's main purpose is to serve as a memory fence to ensure writes made by
423
 * the writer thread are visible prior to readers seeing the m_val change. Its
424
 * secondary purpose is for use with the condition variable for blocking waits */
425
class ThreadSafeInteger
426
{
427
public:
428
429
    ThreadSafeInteger()
430
0
    {
431
0
        m_val = 0;
432
0
        if (pthread_mutex_init(&m_mutex, NULL) ||
433
0
            pthread_cond_init(&m_cond, NULL))
434
0
        {
435
0
            x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
436
0
        }
437
0
    }
438
439
    ~ThreadSafeInteger()
440
0
    {
441
0
        pthread_cond_destroy(&m_cond);
442
0
        pthread_mutex_destroy(&m_mutex);
443
0
    }
444
445
    int waitForChange(int prev)
446
0
    {
447
0
        pthread_mutex_lock(&m_mutex);
448
0
        if (m_val == prev)
449
0
            pthread_cond_wait(&m_cond, &m_mutex);
450
0
        pthread_mutex_unlock(&m_mutex);
451
0
        return m_val;
452
0
    }
453
454
    int get()
455
0
    {
456
0
        pthread_mutex_lock(&m_mutex);
457
0
        int ret = m_val;
458
0
        pthread_mutex_unlock(&m_mutex);
459
0
        return ret;
460
0
    }
461
462
    int getIncr(int n = 1)
463
0
    {
464
0
        pthread_mutex_lock(&m_mutex);
465
0
        int ret = m_val;
466
0
        m_val += n;
467
0
        pthread_mutex_unlock(&m_mutex);
468
0
        return ret;
469
0
    }
470
471
    void set(int newval)
472
0
    {
473
0
        pthread_mutex_lock(&m_mutex);
474
0
        m_val = newval;
475
0
        pthread_cond_broadcast(&m_cond);
476
0
        pthread_mutex_unlock(&m_mutex);
477
0
    }
478
479
    void poke(void)
480
0
    {
481
        /* awaken all waiting threads, but make no change */
482
0
        pthread_mutex_lock(&m_mutex);
483
0
        pthread_cond_broadcast(&m_cond);
484
0
        pthread_mutex_unlock(&m_mutex);
485
0
    }
486
487
    void incr()
488
0
    {
489
0
        pthread_mutex_lock(&m_mutex);
490
0
        m_val++;
491
0
        pthread_cond_broadcast(&m_cond);
492
0
        pthread_mutex_unlock(&m_mutex);
493
0
    }
494
495
    void decr()
496
0
    {
497
0
        pthread_mutex_lock(&m_mutex);
498
0
        m_val--;
499
0
        pthread_cond_broadcast(&m_cond);
500
0
        pthread_mutex_unlock(&m_mutex);
501
0
    }
502
503
protected:
504
505
    pthread_mutex_t m_mutex;
506
    pthread_cond_t  m_cond;
507
    int             m_val;
508
};
509
510
0
#define TIMEOUT_INFINITE 0xFFFFFFFF
511
512
class NamedSemaphore
513
{
514
public:
515
    NamedSemaphore() 
516
        : m_sem(NULL)
517
#ifndef __APPLE__
518
        , m_name(NULL)
519
#endif //__APPLE__
520
0
    {
521
0
    }
522
523
    ~NamedSemaphore()
524
0
    {
525
0
    }
526
527
    bool create(const char* name, const int initcnt, const int maxcnt)
528
0
    {
529
0
        bool ret = false;
530
531
0
        if (initcnt >= maxcnt)
532
0
        {
533
0
            return false;
534
0
        }
535
536
#ifdef __APPLE__
537
        do
538
        {
539
            int32_t pshared = name != NULL ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
540
541
            m_sem = (mac_sem_t *)malloc(sizeof(mac_sem_t));
542
            if (!m_sem)
543
            {
544
                break;
545
            }
546
547
            if (pthread_mutexattr_init(&m_sem->mutexAttr))
548
            {
549
                break;
550
            }
551
552
            if (pthread_mutexattr_setpshared(&m_sem->mutexAttr, pshared))
553
            {
554
                break;
555
            }
556
557
            if (pthread_condattr_init(&m_sem->condAttr))
558
            {
559
                break;
560
            }
561
562
            if (pthread_condattr_setpshared(&m_sem->condAttr, pshared))
563
            {
564
                break;
565
            }
566
567
            if (pthread_mutex_init(&m_sem->mutex, &m_sem->mutexAttr))
568
            {
569
                break;
570
            }
571
572
            if (pthread_cond_init(&m_sem->cond, &m_sem->condAttr))
573
            {
574
                break;
575
            }
576
577
            m_sem->curCnt = initcnt;
578
            m_sem->maxCnt = maxcnt;
579
580
            ret = true;
581
        } while (0);
582
        
583
        if (!ret)
584
        {
585
            release();
586
        }
587
588
#else  //__APPLE__
589
0
        m_sem = sem_open(name, O_CREAT | O_EXCL, 0666, initcnt);
590
0
        if (m_sem != SEM_FAILED) 
591
0
        {
592
0
            m_name = strdup(name);
593
0
            ret = true;
594
0
        }
595
0
        else 
596
0
        {
597
0
            if (EEXIST == errno) 
598
0
            {
599
0
                m_sem = sem_open(name, 0);
600
0
                if (m_sem != SEM_FAILED) 
601
0
                {
602
0
                    m_name = strdup(name);
603
0
                    ret = true;
604
0
                }
605
0
            }
606
0
        }
607
0
#endif //__APPLE__
608
609
0
        return ret;
610
0
    }
611
612
    bool give(const int32_t cnt)
613
0
    {
614
0
        if (!m_sem)
615
0
        {
616
0
            return false;
617
0
        }
618
619
#ifdef __APPLE__
620
        if (pthread_mutex_lock(&m_sem->mutex))
621
        {
622
            return false;
623
        }
624
625
        int oldCnt = m_sem->curCnt;
626
        m_sem->curCnt += cnt;
627
        if (m_sem->curCnt > m_sem->maxCnt)
628
        {
629
            m_sem->curCnt = m_sem->maxCnt;
630
        }
631
632
        bool ret = true;
633
        if (!oldCnt)
634
        {
635
            ret = 0 == pthread_cond_broadcast(&m_sem->cond);
636
        }
637
638
        if (pthread_mutex_unlock(&m_sem->mutex))
639
        {
640
            return false;
641
        }
642
643
        return ret;
644
#else //__APPLE__
645
0
        int ret = 0;
646
0
        int32_t curCnt = cnt;
647
0
        while (curCnt-- && !ret) {
648
0
            ret = sem_post(m_sem);
649
0
        }
650
651
0
        return 0 == ret;
652
0
#endif //_APPLE__
653
0
    }
654
655
    bool take(const uint32_t time_out = TIMEOUT_INFINITE)
656
0
    {
657
0
        if (!m_sem)
658
0
        {
659
0
            return false;
660
0
        }
661
662
#ifdef __APPLE__
663
664
        if (pthread_mutex_lock(&m_sem->mutex))
665
        {
666
            return false;
667
        }
668
669
        bool ret = true;
670
        if (TIMEOUT_INFINITE == time_out) 
671
        {
672
            if (!m_sem->curCnt)
673
            {
674
                if (pthread_cond_wait(&m_sem->cond, &m_sem->mutex))
675
                {
676
                    ret = false;
677
                } 
678
            }
679
680
            if (m_sem->curCnt && ret)
681
            {
682
                m_sem->curCnt--;
683
            }
684
        }
685
        else
686
        {
687
            if (0 == time_out)
688
            {
689
                if (m_sem->curCnt)
690
                {
691
                    m_sem->curCnt--;
692
                }
693
                else
694
                {
695
                    ret = false;
696
                }
697
            }
698
            else
699
            {
700
                if (!m_sem->curCnt)
701
                {
702
                    struct timespec ts;
703
                    ts.tv_sec = time_out / 1000L;
704
                    ts.tv_nsec = (time_out * 1000000L) - ts.tv_sec * 1000 * 1000 * 1000;
705
706
                    if (pthread_cond_timedwait(&m_sem->cond, &m_sem->mutex, &ts))
707
                    {
708
                        ret = false;
709
                    }
710
                }
711
712
                if (m_sem->curCnt && ret)
713
                {
714
                    m_sem->curCnt--;
715
                }
716
            }
717
        }
718
719
        if (pthread_mutex_unlock(&m_sem->mutex))
720
        {
721
            return false;
722
        }
723
724
        return ret;
725
#else //__APPLE__
726
0
        if (TIMEOUT_INFINITE == time_out) 
727
0
        {
728
0
            return 0 == sem_wait(m_sem);
729
0
        }
730
0
        else 
731
0
        {
732
0
            if (0 == time_out)
733
0
            {
734
0
                return 0 == sem_trywait(m_sem);
735
0
            }
736
0
            else
737
0
            {
738
0
                struct timespec ts;
739
0
                ts.tv_sec = time_out / 1000L;
740
0
                ts.tv_nsec = (time_out * 1000000L) - ts.tv_sec * 1000 * 1000 * 1000;
741
0
                return 0 == sem_timedwait(m_sem, &ts);
742
0
            }
743
0
        }
744
0
#endif //_APPLE__
745
0
    }
746
747
    void release()
748
0
    {
749
0
        if (m_sem)
750
0
        {
751
#ifdef __APPLE__
752
            pthread_condattr_destroy(&m_sem->condAttr);
753
            pthread_mutexattr_destroy(&m_sem->mutexAttr);
754
            pthread_mutex_destroy(&m_sem->mutex);
755
            pthread_cond_destroy(&m_sem->cond);
756
            free(m_sem);
757
            m_sem = NULL;
758
#else //__APPLE__
759
0
            sem_close(m_sem);
760
0
            sem_unlink(m_name);
761
0
            m_sem = NULL;
762
0
            free(m_name);
763
0
            m_name = NULL;
764
0
#endif //__APPLE__
765
0
        }
766
0
    }
767
768
private:
769
#ifdef __APPLE__
770
    typedef struct
771
    {
772
        pthread_mutex_t     mutex;
773
        pthread_cond_t      cond;
774
        pthread_mutexattr_t mutexAttr;
775
        pthread_condattr_t  condAttr;
776
        uint32_t            curCnt;
777
        uint32_t            maxCnt;
778
    }mac_sem_t;
779
    mac_sem_t *m_sem;
780
#else // __APPLE__
781
    sem_t *m_sem;
782
    char  *m_name;
783
#endif // __APPLE_
784
};
785
786
#endif // ifdef _WIN32
787
788
class ScopedLock
789
{
790
public:
791
792
0
    ScopedLock(Lock &instance) : inst(instance)
793
0
    {
794
0
        this->inst.acquire();
795
0
    }
796
797
    ~ScopedLock()
798
0
    {
799
0
        this->inst.release();
800
0
    }
801
802
protected:
803
804
    // do not allow assignments
805
    ScopedLock &operator =(const ScopedLock &);
806
807
    Lock &inst;
808
};
809
810
// Utility class which adds elapsed time of the scope of the object into the
811
// accumulator provided to the constructor
812
struct ScopedElapsedTime
813
{
814
0
    ScopedElapsedTime(int64_t& accum) : accumlatedTime(accum) { startTime = x265_mdate(); }
815
816
0
    ~ScopedElapsedTime() { accumlatedTime += x265_mdate() - startTime; }
817
818
protected:
819
820
    int64_t  startTime;
821
    int64_t& accumlatedTime;
822
823
    // do not allow assignments
824
    ScopedElapsedTime &operator =(const ScopedElapsedTime &);
825
};
826
827
//< Simplistic portable thread class.  Shutdown signalling left to derived class
828
class Thread
829
{
830
private:
831
832
    ThreadHandle thread;
833
834
public:
835
836
    Thread();
837
838
    virtual ~Thread();
839
840
    //< Derived class must implement ThreadMain.
841
    virtual void threadMain() = 0;
842
843
    //< Returns true if thread was successfully created
844
    bool start();
845
846
    void stop();
847
};
848
} // end namespace X265_NS
849
850
#endif // ifndef X265_THREADING_H