]> Sergey Matveev's repositories - bfs.git/blob - src/thread.h
bfstd: Add a thread-safe wrapper for strerror()
[bfs.git] / src / thread.h
1 // Copyright © Tavian Barnes <tavianator@tavianator.com>
2 // SPDX-License-Identifier: 0BSD
3
4 /**
5  * Wrappers for POSIX threading APIs.
6  */
7
8 #ifndef BFS_THREAD_H
9 #define BFS_THREAD_H
10
11 #include "bfstd.h"
12 #include "config.h"
13 #include "diag.h"
14 #include <errno.h>
15 #include <pthread.h>
16 #include <string.h>
17
18 #if __STDC_VERSION__ < 202311L && !defined(thread_local)
19 #  if BFS_USE_THREADS_H
20 #    include <threads.h>
21 #  else
22 #    define thread_local _Thread_local
23 #  endif
24 #endif
25
26 #define thread_verify(expr, cond) \
27         bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, xstrerror(errno))
28
29 /**
30  * Wrapper for pthread_create().
31  *
32  * @return
33  *         0 on success, -1 on error.
34  */
35 #define thread_create(thread, attr, fn, arg) \
36         ((errno = pthread_create(thread, attr, fn, arg)) ? -1 : 0)
37
38 /**
39  * Wrapper for pthread_join().
40  */
41 #define thread_join(thread, ret) \
42         thread_verify(pthread_join(thread, ret), errno == 0)
43
44 /**
45  * Wrapper for pthread_mutex_init().
46  */
47 #define mutex_init(mutex, attr) \
48         ((errno = pthread_mutex_init(mutex, attr)) ? -1 : 0)
49
50 /**
51  * Wrapper for pthread_mutex_lock().
52  */
53 #define mutex_lock(mutex) \
54         thread_verify(pthread_mutex_lock(mutex), errno == 0)
55
56 /**
57  * Wrapper for pthread_mutex_trylock().
58  *
59  * @return
60  *         Whether the mutex was locked.
61  */
62 #define mutex_trylock(mutex) \
63         (thread_verify(pthread_mutex_trylock(mutex), errno == 0 || errno == EBUSY), errno == 0)
64
65 /**
66  * Wrapper for pthread_mutex_unlock().
67  */
68 #define mutex_unlock(mutex) \
69         thread_verify(pthread_mutex_unlock(mutex), errno == 0)
70
71 /**
72  * Wrapper for pthread_mutex_destroy().
73  */
74 #define mutex_destroy(mutex) \
75         thread_verify(pthread_mutex_destroy(mutex), errno == 0)
76
77 /**
78  * Wrapper for pthread_cond_init().
79  */
80 #define cond_init(cond, attr) \
81         ((errno = pthread_cond_init(cond, attr)) ? -1 : 0)
82
83 /**
84  * Wrapper for pthread_cond_wait().
85  */
86 #define cond_wait(cond, mutex) \
87         thread_verify(pthread_cond_wait(cond, mutex), errno == 0)
88
89 /**
90  * Wrapper for pthread_cond_signal().
91  */
92 #define cond_signal(cond) \
93         thread_verify(pthread_cond_signal(cond), errno == 0)
94
95 /**
96  * Wrapper for pthread_cond_broadcast().
97  */
98 #define cond_broadcast(cond) \
99         thread_verify(pthread_cond_broadcast(cond), errno == 0)
100
101 /**
102  * Wrapper for pthread_cond_destroy().
103  */
104 #define cond_destroy(cond) \
105         thread_verify(pthread_cond_destroy(cond), errno == 0)
106
107 /**
108  * Wrapper for pthread_once().
109  */
110 #define invoke_once(once, fn) \
111         thread_verify(pthread_once(once, fn), errno == 0)
112
113 #endif // BFS_THREAD_H