Coverage Report

Created: 2022-08-24 06:15

/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
 *
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
2.69M
#define CLZ(id, x)            id = (unsigned long)__builtin_clz(x) ^ 31
75
191k
#define CTZ(id, x)            id = (unsigned long)__builtin_ctz(x)
76
12.1k
#define ATOMIC_OR(ptr, mask)  __sync_fetch_and_or(ptr, mask)
77
6.55k
#define ATOMIC_AND(ptr, mask) __sync_fetch_and_and(ptr, mask)
78
28.4k
#define ATOMIC_INC(ptr)       __sync_add_and_fetch((volatile int32_t*)ptr, 1)
79
7.25k
#define ATOMIC_DEC(ptr)       __sync_add_and_fetch((volatile int32_t*)ptr, -1)
80
13.9k
#define ATOMIC_ADD(ptr, val)  __sync_fetch_and_add((volatile int32_t*)ptr, val)
81
0
#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
109
    Lock()
110
    {
111
        InitializeCriticalSection(&this->handle);
112
    }
113
114
    ~Lock()
115
    {
116
        DeleteCriticalSection(&this->handle);
117
    }
118
119
    void acquire()
120
    {
121
        EnterCriticalSection(&this->handle);
122
    }
123
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
138
    Event()
139
    {
140
        this->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
141
    }
142
143
    ~Event()
144
    {
145
        CloseHandle(this->handle);
146
    }
147
148
    void wait()
149
    {
150
        WaitForSingleObject(this->handle, INFINITE);
151
    }
152
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
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
178
    ThreadSafeInteger()
179
    {
180
        m_val = 0;
181
        InitializeCriticalSection(&m_cs);
182
        InitializeConditionVariable(&m_cv);
183
    }
184
185
    ~ThreadSafeInteger()
186
    {
187
        DeleteCriticalSection(&m_cs);
188
        XP_CONDITION_VAR_FREE(&m_cv);
189
    }
190
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
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
217
    void set(int newval)
218
    {
219
        EnterCriticalSection(&m_cs);
220
        m_val = newval;
221
        WakeAllConditionVariable(&m_cv);
222
        LeaveCriticalSection(&m_cs);
223
    }
224
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
233
    void incr()
234
    {
235
        EnterCriticalSection(&m_cs);
236
        m_val++;
237
        WakeAllConditionVariable(&m_cv);
238
        LeaveCriticalSection(&m_cs);
239
    }
240
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
42.9k
    {
266
42.9k
        pthread_mutex_init(&this->handle, NULL);
267
42.9k
    }
268
269
    ~Lock()
270
42.9k
    {
271
42.9k
        pthread_mutex_destroy(&this->handle);
272
42.9k
    }
273
274
    void acquire()
275
45.7k
    {
276
45.7k
        pthread_mutex_lock(&this->handle);
277
45.7k
    }
278
279
    void release()
280
45.7k
    {
281
45.7k
        pthread_mutex_unlock(&this->handle);
282
45.7k
    }
283
284
protected:
285
286
    pthread_mutex_t handle;
287
};
288
289
class Event
290
{
291
public:
292
293
    Event()
294
33.7k
    {
295
33.7k
        m_counter = 0;
296
33.7k
        if (pthread_mutex_init(&m_mutex, NULL) ||
297
33.7k
            pthread_cond_init(&m_cond, NULL))
298
0
        {
299
0
            x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
300
0
        }
301
33.7k
    }
302
303
    ~Event()
304
33.7k
    {
305
33.7k
        pthread_cond_destroy(&m_cond);
306
33.7k
        pthread_mutex_destroy(&m_mutex);
307
33.7k
    }
308
309
    void wait()
310
40.0k
    {
311
40.0k
        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
80.0k
        while (!m_counter)
316
40.0k
            pthread_cond_wait(&m_cond, &m_mutex);
317
318
40.0k
        m_counter--;
319
40.0k
        pthread_mutex_unlock(&m_mutex);
320
40.0k
    }
321
322
    bool timedWait(uint32_t waitms)
323
584
    {
324
584
        bool bTimedOut = false;
325
326
584
        pthread_mutex_lock(&m_mutex);
327
584
        if (!m_counter)
328
584
        {
329
584
            struct timeval tv;
330
584
            struct timespec ts;
331
584
            gettimeofday(&tv, NULL);
332
            /* convert current time from (sec, usec) to (sec, nsec) */
333
584
            ts.tv_sec = tv.tv_sec;
334
584
            ts.tv_nsec = tv.tv_usec * 1000;
335
336
584
            ts.tv_nsec += 1000 * 1000 * (waitms % 1000);    /* add ms to tv_nsec */
337
584
            ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000); /* overflow tv_nsec */
338
584
            ts.tv_nsec %= (1000 * 1000 * 1000);             /* clamp tv_nsec */
339
584
            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
584
            bTimedOut = pthread_cond_timedwait(&m_cond, &m_mutex, &ts) == ETIMEDOUT;
345
584
        }
346
584
        if (m_counter > 0)
347
584
        {
348
584
            m_counter--;
349
584
            bTimedOut = false;
350
584
        }
351
584
        pthread_mutex_unlock(&m_mutex);
352
584
        return bTimedOut;
353
584
    }
354
355
    void trigger()
356
40.7k
    {
357
40.7k
        pthread_mutex_lock(&m_mutex);
358
40.7k
        if (m_counter < UINT_MAX)
359
40.7k
            m_counter++;
360
        /* Signal a single blocking thread */
361
40.7k
        pthread_cond_signal(&m_cond);
362
40.7k
        pthread_mutex_unlock(&m_mutex);
363
40.7k
    }
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
56.0k
    {
383
56.0k
        m_val = 0;
384
56.0k
        if (pthread_mutex_init(&m_mutex, NULL) ||
385
56.0k
            pthread_cond_init(&m_cond, NULL))
386
0
        {
387
0
            x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
388
0
        }
389
56.0k
    }
390
391
    ~ThreadSafeInteger()
392
56.0k
    {
393
56.0k
        pthread_cond_destroy(&m_cond);
394
56.0k
        pthread_mutex_destroy(&m_mutex);
395
56.0k
    }
396
397
    int waitForChange(int prev)
398
12
    {
399
12
        pthread_mutex_lock(&m_mutex);
400
12
        if (m_val == prev)
401
12
            pthread_cond_wait(&m_cond, &m_mutex);
402
12
        pthread_mutex_unlock(&m_mutex);
403
12
        return m_val;
404
12
    }
405
406
    int get()
407
46.2k
    {
408
46.2k
        pthread_mutex_lock(&m_mutex);
409
46.2k
        int ret = m_val;
410
46.2k
        pthread_mutex_unlock(&m_mutex);
411
46.2k
        return ret;
412
46.2k
    }
413
414
    int getIncr(int n = 1)
415
0
    {
416
0
        pthread_mutex_lock(&m_mutex);
417
0
        int ret = m_val;
418
0
        m_val += n;
419
0
        pthread_mutex_unlock(&m_mutex);
420
0
        return ret;
421
0
    }
422
423
    void set(int newval)
424
65.9k
    {
425
65.9k
        pthread_mutex_lock(&m_mutex);
426
65.9k
        m_val = newval;
427
65.9k
        pthread_cond_broadcast(&m_cond);
428
65.9k
        pthread_mutex_unlock(&m_mutex);
429
65.9k
    }
430
431
    void poke(void)
432
4.56k
    {
433
        /* awaken all waiting threads, but make no change */
434
4.56k
        pthread_mutex_lock(&m_mutex);
435
4.56k
        pthread_cond_broadcast(&m_cond);
436
4.56k
        pthread_mutex_unlock(&m_mutex);
437
4.56k
    }
438
439
    void incr()
440
16.7k
    {
441
16.7k
        pthread_mutex_lock(&m_mutex);
442
16.7k
        m_val++;
443
16.7k
        pthread_cond_broadcast(&m_cond);
444
16.7k
        pthread_mutex_unlock(&m_mutex);
445
16.7k
    }
446
447
    void decr()
448
0
    {
449
0
        pthread_mutex_lock(&m_mutex);
450
0
        m_val--;
451
0
        pthread_cond_broadcast(&m_cond);
452
0
        pthread_mutex_unlock(&m_mutex);
453
0
    }
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
468
    ScopedLock(Lock &instance) : inst(instance)
469
26.7k
    {
470
26.7k
        this->inst.acquire();
471
26.7k
    }
472
473
    ~ScopedLock()
474
26.7k
    {
475
26.7k
        this->inst.release();
476
26.7k
    }
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
{
490
0
    ScopedElapsedTime(int64_t& accum) : accumlatedTime(accum) { startTime = x265_mdate(); }
491
492
0
    ~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