Clean up the Chorus a little
[openal-soft.git] / common / threads.h
blob8fd1093d6d46790c3cd8e0bee435d5b55f4c3fff
1 #ifndef AL_THREADS_H
2 #define AL_THREADS_H
4 #include <time.h>
6 #if defined(__GNUC__) && defined(__i386__)
7 /* force_align_arg_pointer is required for proper function arguments aligning
8 * when SSE code is used. Some systems (Windows, QNX) do not guarantee our
9 * thread functions will be properly aligned on the stack, even though GCC may
10 * generate code with the assumption that it is. */
11 #define FORCE_ALIGN __attribute__((force_align_arg_pointer))
12 #else
13 #define FORCE_ALIGN
14 #endif
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
20 enum {
21 althrd_success = 0,
22 althrd_error,
23 althrd_nomem,
24 althrd_timedout,
25 althrd_busy
28 enum {
29 almtx_plain = 0,
30 almtx_recursive = 1,
33 typedef int (*althrd_start_t)(void*);
36 #ifdef _WIN32
37 #define WIN32_LEAN_AND_MEAN
38 #include <windows.h>
40 typedef DWORD althrd_t;
41 typedef CRITICAL_SECTION almtx_t;
42 typedef HANDLE alsem_t;
45 inline void althrd_yield(void)
47 SwitchToThread();
51 inline int almtx_lock(almtx_t *mtx)
53 if(!mtx) return althrd_error;
54 EnterCriticalSection(mtx);
55 return althrd_success;
58 inline int almtx_unlock(almtx_t *mtx)
60 if(!mtx) return althrd_error;
61 LeaveCriticalSection(mtx);
62 return althrd_success;
65 #else
67 #include <stdint.h>
68 #include <errno.h>
69 #include <pthread.h>
70 #ifdef __APPLE__
71 #include <dispatch/dispatch.h>
72 #else /* !__APPLE__ */
73 #include <semaphore.h>
74 #endif /* __APPLE__ */
76 typedef pthread_t althrd_t;
77 typedef pthread_mutex_t almtx_t;
78 #ifdef __APPLE__
79 typedef dispatch_semaphore_t alsem_t;
80 #else /* !__APPLE__ */
81 typedef sem_t alsem_t;
82 #endif /* __APPLE__ */
85 inline void althrd_yield(void)
87 sched_yield();
91 inline int almtx_lock(almtx_t *mtx)
93 if(pthread_mutex_lock(mtx) != 0)
94 return althrd_error;
95 return althrd_success;
98 inline int almtx_unlock(almtx_t *mtx)
100 if(pthread_mutex_unlock(mtx) != 0)
101 return althrd_error;
102 return althrd_success;
105 #endif
108 int althrd_create(althrd_t *thr, althrd_start_t func, void *arg);
109 int althrd_detach(althrd_t thr);
110 int althrd_join(althrd_t thr, int *res);
111 void althrd_setname(const char *name);
113 int almtx_init(almtx_t *mtx, int type);
114 void almtx_destroy(almtx_t *mtx);
116 int alsem_init(alsem_t *sem, unsigned int initial);
117 void alsem_destroy(alsem_t *sem);
118 int alsem_post(alsem_t *sem);
119 int alsem_wait(alsem_t *sem);
120 int alsem_trywait(alsem_t *sem);
122 #ifdef __cplusplus
123 } // extern "C"
125 #include <mutex>
127 /* Add specializations for std::lock_guard and std::unique_lock which take an
128 * almtx_t and call the appropriate almtx_* functions.
130 namespace std {
132 template<>
133 class lock_guard<almtx_t> {
134 almtx_t &mMtx;
136 public:
137 using mutex_type = almtx_t;
139 explicit lock_guard(almtx_t &mtx) : mMtx(mtx) { almtx_lock(&mMtx); }
140 lock_guard(almtx_t &mtx, std::adopt_lock_t) noexcept : mMtx(mtx) { }
141 ~lock_guard() { almtx_unlock(&mMtx); }
143 lock_guard(const lock_guard&) = delete;
144 lock_guard& operator=(const lock_guard&) = delete;
147 template<>
148 class unique_lock<almtx_t> {
149 almtx_t *mMtx{nullptr};
150 bool mLocked{false};
152 public:
153 using mutex_type = almtx_t;
155 unique_lock() noexcept = default;
156 explicit unique_lock(almtx_t &mtx) : mMtx(&mtx) { almtx_lock(mMtx); mLocked = true; }
157 unique_lock(unique_lock&& rhs) noexcept : mMtx(rhs.mMtx), mLocked(rhs.mLocked)
158 { rhs.mMtx = nullptr; rhs.mLocked = false; }
159 ~unique_lock() { if(mLocked) almtx_unlock(mMtx); }
161 unique_lock& operator=(const unique_lock&) = delete;
162 unique_lock& operator=(unique_lock&& rhs)
164 if(mLocked)
165 almtx_unlock(mMtx);
166 mMtx = rhs.mMtx; rhs.mMtx = nullptr;
167 mLocked = rhs.mLocked; rhs.mLocked = false;
168 return *this;
171 void lock()
173 almtx_lock(mMtx);
174 mLocked = true;
176 void unlock()
178 mLocked = false;
179 almtx_unlock(mMtx);
183 } // namespace std
184 #endif
186 #endif /* AL_THREADS_H */