Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/include/gpac/thread.h
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2023
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / common tools sub-project
9
 *
10
 *  GPAC is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU Lesser General Public License as published by
12
 *  the Free Software Foundation; either version 2, or (at your option)
13
 *  any later version.
14
 *
15
 *  GPAC is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; see the file COPYING.  If not, write to
22
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 */
25
26
#ifndef _GF_THREAD_H_
27
#define _GF_THREAD_H_
28
29
#ifdef __cplusplus
30
extern "C" {
31
#endif
32
33
/*!
34
\file <gpac/thread.h>
35
\brief Threading and Mutual Exclusion
36
*/
37
38
/*!
39
\addtogroup thr_grp
40
\brief Threading and Mutual Exclusion
41
42
This section documents the threading of the GPAC framework. These provide an easy way to implement
43
safe multithreaded tools.
44
45
Available tools are thread, mutex and semaphore
46
47
\defgroup thread_grp Thread
48
\ingroup thr_grp
49
\defgroup mutex_grp Mutex
50
\ingroup thr_grp
51
\defgroup sema_grp Semaphore
52
\ingroup thr_grp
53
*/
54
55
/*!
56
\addtogroup thread_grp
57
\brief Thread processing
58
59
The thread object allows executing some code independently of the main process of your application.
60
@{
61
*/
62
63
#include <gpac/tools.h>
64
65
66
 //atomic ref_count++ / ref_count--
67
#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
68
#include <windows.h>
69
#include <winbase.h>
70
71
72
#ifdef GPAC_BUILD_FOR_WINXP
73
74
/* Addendum by M. Lackner: Wrap InterlockedExchangeAdd64() around
75
   InterlockedCompareExchange64() and name it specifically as an XP
76
   function for 32-bit builds only */
77
#ifndef GPAC_64_BITS
78
#pragma intrinsic(_InterlockedCompareExchange64)
79
#define InterlockedCompareExchange64xp _InterlockedCompareExchange64
80
static inline LONGLONG InterlockedExchangeAdd64xp(_Inout_ LONGLONG volatile *Addend, _In_ LONGLONG Value)
81
{
82
  LONGLONG Old;
83
  do {
84
    Old = *Addend;
85
  } while (InterlockedCompareExchange64xp(Addend, Old + Value, Old) != Old);
86
  return Old;
87
}
88
#endif
89
/* End of addendum */
90
91
92
/*! atomic integer increment */
93
#define safe_int_inc(__v) InterlockedIncrement((int *) (__v))
94
/*! atomic integer decrement */
95
#define safe_int_dec(__v) InterlockedDecrement((int *) (__v))
96
/*! atomic integer addition */
97
98
/* Modified by M. Lackner for XP & XP x64 compatibility */
99
/* InterlockedAdd and InterlockedAdd64 do not exist on Win XP, so we use
100
the older InterlockedExchangeAdd and a newly written InterlockedExchangeAdd64xp
101
static inline function.
102
See:
103
https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangeadd
104
https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangeadd64
105
*/
106
107
#define safe_int_add(__v, inc_val) InterlockedExchangeAdd((int *) (__v), inc_val)
108
#define safe_int_sub(__v, dec_val) InterlockedExchangeAdd((int *) (__v), -dec_val)
109
/*! atomic add and gets the value *before* the add */
110
#define safe_int_fetch_add(__v, inc_val) InterlockedExchangeAdd((int *) (__v), inc_val)
111
#ifdef GPAC_64_BITS
112
#define safe_int64_add(__v, inc_val) InterlockedExchangeAdd64((LONGLONG *) (__v), inc_val)
113
#define safe_int64_sub(__v, dec_val) InterlockedExchangeAdd64((LONGLONG *) (__v), -dec_val)
114
#else
115
#define safe_int64_add(__v, inc_val) InterlockedExchangeAdd64xp((LONGLONG *) (__v), inc_val)
116
#define safe_int64_sub(__v, dec_val) InterlockedExchangeAdd64xp((LONGLONG *) (__v), -dec_val)
117
#endif
118
/* End of modification by M. Lackner */
119
120
#else //not winxp
121
122
/*! atomic integer increment */
123
#define safe_int_inc(__v) InterlockedIncrement((int *) (__v))
124
/*! atomic integer decrement */
125
#define safe_int_dec(__v) InterlockedDecrement((int *) (__v))
126
/*! atomic integer addition */
127
#define safe_int_add(__v, inc_val) InterlockedAdd((int *) (__v), inc_val)
128
/*! atomic integer subtraction */
129
#define safe_int_sub(__v, dec_val) InterlockedAdd((int *) (__v), -dec_val)
130
/*! atomic large integer addition */
131
#define safe_int64_add(__v, inc_val) InterlockedAdd64((LONG64 *) (__v), inc_val)
132
/*! atomic large integer subtraction */
133
#define safe_int64_sub(__v, dec_val) InterlockedAdd64((LONG64 *) (__v), -dec_val)
134
/*! atomic add and gets the value *before* the add */
135
#define safe_int_fetch_add(__v, inc_val) InterlockedExchangeAdd((int *) (__v), inc_val)
136
#endif //winxp
137
138
#else //not windows
139
140
#ifdef GPAC_NEED_LIBATOMIC
141
142
/*! atomic integer increment */
143
#define safe_int_inc(__v) __atomic_add_fetch((int *) (__v), 1, __ATOMIC_SEQ_CST)
144
/*! atomic integer decrement */
145
#define safe_int_dec(__v) __atomic_sub_fetch((int *) (__v), 1, __ATOMIC_SEQ_CST)
146
/*! atomic integer addition */
147
#define safe_int_add(__v, inc_val) __atomic_add_fetch((int *) (__v), inc_val, __ATOMIC_SEQ_CST)
148
/*! atomic integer subtraction */
149
#define safe_int_sub(__v, dec_val) __atomic_sub_fetch((int *) (__v), dec_val, __ATOMIC_SEQ_CST)
150
/*! atomic large integer addition */
151
#define safe_int64_add(__v, inc_val) __atomic_add_fetch((int64_t *) (__v), inc_val, __ATOMIC_SEQ_CST)
152
/*! atomic large integer subtraction */
153
#define safe_int64_sub(__v, dec_val) __atomic_sub_fetch((int64_t *) (__v), dec_val, __ATOMIC_SEQ_CST)
154
/*! atomic add and gets the value *before* the add */
155
#define safe_int_fetch_add(__v, inc_val) __atomic_fetch_add((int *) (__v), inc_val, __ATOMIC_SEQ_CST)
156
157
#else
158
159
/*! atomic integer increment */
160
1.71M
#define safe_int_inc(__v) __sync_add_and_fetch((int *) (__v), 1)
161
/*! atomic integer decrement */
162
1.71M
#define safe_int_dec(__v) __sync_sub_and_fetch((int *) (__v), 1)
163
/*! atomic integer addition */
164
#define safe_int_add(__v, inc_val) __sync_add_and_fetch((int *) (__v), inc_val)
165
/*! atomic integer subtraction */
166
0
#define safe_int_sub(__v, dec_val) __sync_sub_and_fetch((int *) (__v), dec_val)
167
/*! atomic large integer addition */
168
0
#define safe_int64_add(__v, inc_val) __sync_add_and_fetch((int64_t *) (__v), inc_val)
169
/*! atomic large integer subtraction */
170
0
#define safe_int64_sub(__v, dec_val) __sync_sub_and_fetch((int64_t *) (__v), dec_val)
171
/*! atomic add and gets the value *before* the add */
172
240
#define safe_int_fetch_add(__v, inc_val) __sync_fetch_and_add((int *) (__v), inc_val)
173
174
#endif //GPAC_NEED_LIBATOMIC
175
176
#endif
177
178
179
/*!
180
\brief Thread states
181
 *
182
 *Indicates the execution status of a thread
183
 */
184
enum
185
{
186
  /*! the thread has been initialized but is not started yet*/
187
  GF_THREAD_STATUS_STOP = 0,
188
  /*! the thread is running*/
189
  GF_THREAD_STATUS_RUN = 1,
190
  /*! the thread has exited its body function*/
191
  GF_THREAD_STATUS_DEAD = 2
192
};
193
194
/*! thread priorities */
195
enum
196
{
197
  /*!Idle Priority*/
198
  GF_THREAD_PRIORITY_IDLE=0,
199
  /*!Less Idle Priority*/
200
  GF_THREAD_PRIORITY_LESS_IDLE,
201
  /*!Lowest Priority*/
202
  GF_THREAD_PRIORITY_LOWEST,
203
  /*!Low Priority*/
204
  GF_THREAD_PRIORITY_LOW,
205
  /*!Normal Priority (the default one)*/
206
  GF_THREAD_PRIORITY_NORMAL,
207
  /*!High Priority*/
208
  GF_THREAD_PRIORITY_HIGH,
209
  /*!Highest Priority*/
210
  GF_THREAD_PRIORITY_HIGHEST,
211
  /*!First real-time priority*/
212
  GF_THREAD_PRIORITY_REALTIME,
213
  /*!Last real-time priority*/
214
  GF_THREAD_PRIORITY_REALTIME_END=255
215
};
216
217
218
/*!
219
\brief thread run function callback
220
221
The gf_thread_run type is the type for the callback of the \ref gf_thread_run function
222
\param par opaque user data
223
\return exit code of the thread, usually 1 for error and 0 if normal execution
224
 */
225
typedef u32 (*gf_thread_run)(void *par);
226
227
228
#ifndef GPAC_DISABLE_THREADS
229
230
/*!
231
\brief abstracted thread object
232
*/
233
typedef struct __tag_thread GF_Thread;
234
235
/*!
236
\brief thread constructor
237
238
Constructs a new thread object
239
\param name log name of the thread if any
240
\return new thread object
241
 */
242
GF_Thread *gf_th_new(const char *name);
243
/*!
244
\brief thread destructor
245
246
Kills the thread if running and destroys the object
247
\param th the thread object
248
 */
249
void gf_th_del(GF_Thread *th);
250
251
/*!
252
\brief thread execution
253
254
Executes the thread with the given function
255
\note A thread may be run several times but cannot be run twice in the same time.
256
\param th the thread object
257
\param run the function this thread will call
258
\param par the argument to the function the thread will call
259
\return error if any
260
 */
261
GF_Err gf_th_run(GF_Thread *th, gf_thread_run run, void *par);
262
/*!
263
\brief thread stopping
264
265
Waits for the thread exit until return
266
\param th the thread object
267
 */
268
void gf_th_stop(GF_Thread *th);
269
/*!
270
\brief thread status query
271
272
Gets the thread status
273
\param th the thread object
274
\return thread status
275
 */
276
u32 gf_th_status(GF_Thread *th);
277
278
/*!
279
\brief thread priority
280
281
Sets the thread execution priority level.
282
\param th the thread object
283
\param priority the desired priority
284
\note this should be used with caution, especially use of real-time priorities.
285
 */
286
void gf_th_set_priority(GF_Thread *th, s32 priority);
287
/*!
288
\brief current thread ID
289
290
Gets the ID of the current thread the caller is in.
291
\return thread ID
292
*/
293
u32 gf_th_id();
294
295
#ifdef GPAC_CONFIG_ANDROID
296
/*! Register a function that will be called before pthread_exist is called */
297
GF_Err gf_register_before_exit_function(GF_Thread *t, u32 (*toRunBeforePthreadExit)(void *param));
298
299
/*! Get the current Thread if any. May return NULL
300
 */
301
GF_Thread * gf_th_current();
302
303
#endif /* GPAC_CONFIG_ANDROID */
304
305
/*! @} */
306
307
/*!
308
\addtogroup mutex_grp
309
\brief Mutual exclusion
310
311
The mutex object allows ensuring that portions of the code (typically access to variables) cannot be executed by two threads (or a thread and the main process) at the same time.
312
313
@{
314
*/
315
316
/*!
317
\brief abstracted mutex object*/
318
typedef struct __tag_mutex GF_Mutex;
319
/*!
320
\brief mutex constructor
321
322
Contructs a new mutex object
323
\param name log name of the thread if any
324
\return new mutex
325
*/
326
GF_Mutex *gf_mx_new(const char *name);
327
/*!
328
\brief mutex denstructor
329
330
Destroys a mutex object. This will wait for the mutex to be released if needed.
331
\param mx the mutex object, may be NULL
332
*/
333
void gf_mx_del(GF_Mutex *mx);
334
/*!
335
\brief mutex locking
336
337
Locks the mutex object, making sure that another thread locking this mutex cannot execute until the mutex is unlocked.
338
\param mx the mutex object, may be NULL
339
\return 1 if success or mutex is NULL, 0 if error locking the mutex (which should never happen)
340
*/
341
u32 gf_mx_p(GF_Mutex *mx);
342
/*!
343
\brief mutex unlocking
344
345
Unlocks the mutex object, allowing other threads waiting on this mutex to continue their execution
346
\param mx the mutex object, may be NULL
347
*/
348
void gf_mx_v(GF_Mutex *mx);
349
/*!
350
\brief mutex non-blocking lock
351
352
Attemps to lock the mutex object without blocking until the object is released.
353
\param mx the mutex object, may be NULL
354
\return GF_TRUE if the mutex has been successfully locked or if the mutex is NULL, in which case it shall then be unlocked, or GF_FALSE if the mutex is locked by another thread.
355
*/
356
Bool gf_mx_try_lock(GF_Mutex *mx);
357
358
/*!
359
\brief get mutex number of locks
360
361
Returns the number of locks on the mutex if the caller thread is holding the mutex.
362
\param mx the mutex object, may be NULL
363
\return -1 if the mutex is not hold by the calling thread, or the number of locks (possibly 0) otherwise. Returns 0 if mutex is NULL
364
 */
365
s32 gf_mx_get_num_locks(GF_Mutex *mx);
366
367
/*! @} */
368
369
/*!
370
\addtogroup sema_grp
371
\brief Semaphore
372
373
374
The semaphore object allows controlling how portions of the code (typically access to variables) are
375
 executed by two threads (or a thread and the main process) at the same time. The best image for a semaphore is a limited set
376
 of money coins (always easy to understand hmm?). If no money is in the set, nobody can buy anything until a coin is put back in the set.
377
 When the set is full, the money is wasted (call it "the bank"...).
378
379
@{
380
*/
381
382
/*********************************************************************
383
          Semaphore Object
384
**********************************************************************/
385
/*!
386
\brief abstracted semaphore object
387
*/
388
typedef struct __tag_semaphore GF_Semaphore;
389
/*!
390
\brief semaphore constructor
391
392
Constructs a new semaphore object
393
\param MaxCount the maximum notification count of this semaphore
394
\param InitCount the initial notification count of this semaphore upon construction
395
\return the semaphore object
396
 */
397
GF_Semaphore *gf_sema_new(u32 MaxCount, u32 InitCount);
398
/*!
399
\brief semaphore destructor
400
401
Destructs the semaphore object. This will wait for the semaphore to be released if needed.
402
\param sm the semaphore object
403
 */
404
void gf_sema_del(GF_Semaphore *sm);
405
/*!
406
\brief semaphore notification.
407
408
Notifies the semaphore of a certain amount of releases.
409
\param sm the semaphore object
410
\param nb_rel sm the number of release to notify
411
\return GF_TRUE if success, GF_FALSE otherwise
412
*/
413
Bool gf_sema_notify(GF_Semaphore *sm, u32 nb_rel);
414
/*!
415
\brief semaphore wait
416
417
Waits for the semaphore to be accessible (eg, may wait an infinite time).
418
\param sm the semaphore object
419
\return GF_TRUE if successful wait, GF_FALSE if wait failed
420
*/
421
Bool gf_sema_wait(GF_Semaphore *sm);
422
/*!
423
\brief semaphore time wait
424
425
Waits for a certain for the semaphore to be accessible, and returns when semaphore is accessible or wait time has passed.
426
\param sm the semaphore object
427
\param time_out the amount of time to wait for the release in milliseconds
428
\return returns 1 if the semaphore was released before the timeout, 0 if the semaphore is still not released after the timeout.
429
*/
430
Bool gf_sema_wait_for(GF_Semaphore *sm, u32 time_out);
431
432
433
#else
434
435
typedef void * GF_Thread;
436
#define gf_th_new(_name) NULL
437
#define gf_th_del(_th)
438
#define gf_th_run(_th, _run, _par) GF_OK
439
#define gf_th_stop(_th)
440
#define gf_th_status(_th) GF_THREAD_STATUS_DEAD
441
#define gf_th_set_priority(_th, _priority)
442
#define gf_th_id() 0
443
444
#ifdef GPAC_CONFIG_ANDROID
445
#define gf_register_before_exit_function(_t, _fun)
446
#define gf_th_current() NULL
447
#endif /* GPAC_CONFIG_ANDROID */
448
449
typedef void *GF_Mutex;
450
#define gf_mx_new(_name) NULL
451
#define gf_mx_del(_mx)
452
#define gf_mx_p(_mx) 1
453
#define gf_mx_v(_mx)
454
#define gf_mx_try_lock(_mx) GF_TRUE
455
#define gf_mx_get_num_locks(_mx) 0
456
457
typedef void *GF_Semaphore;
458
#define gf_sema_new(_MaxCount, _InitCount) NULL
459
#define gf_sema_del(_sm)
460
#define gf_sema_notify(_sm, _nb_rel) GF_TRUE
461
#define gf_sema_wait(_sm) GF_TRUE
462
#define gf_sema_wait_for(_sm, _time_out) GF_TRUE
463
464
#endif
465
466
467
/*! @} */
468
469
#ifdef __cplusplus
470
}
471
#endif
472
473
474
#endif    /*_GF_THREAD_H_*/