1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3
4#ifndef BASE_SPHORE_H
5#define BASE_SPHORE_H
6
7#include "detect.h"
8
9#include <atomic>
10
11/**
12 * @defgroup Semaphore Semaphores
13 *
14 * @see Threads
15 */
16
17#if defined(CONF_FAMILY_WINDOWS)
18typedef void *SEMAPHORE;
19#elif defined(CONF_PLATFORM_MACOS)
20#include <semaphore.h>
21typedef sem_t *SEMAPHORE;
22#elif defined(CONF_FAMILY_UNIX)
23#include <semaphore.h>
24typedef sem_t SEMAPHORE;
25#else
26#error not implemented on this platform
27#endif
28
29/**
30 * @ingroup Semaphore
31 */
32void sphore_init(SEMAPHORE *sem);
33
34/**
35 * @ingroup Semaphore
36 */
37void sphore_wait(SEMAPHORE *sem);
38
39/**
40 * @ingroup Semaphore
41 */
42void sphore_signal(SEMAPHORE *sem);
43
44/**
45 * @ingroup Semaphore
46 */
47void sphore_destroy(SEMAPHORE *sem);
48
49class CSemaphore
50{
51 SEMAPHORE m_Sem;
52 // implement the counter separately, because the `sem_getvalue`-API is
53 // deprecated on macOS: https://stackoverflow.com/a/16655541
54 std::atomic_int m_Count{0};
55
56public:
57 CSemaphore() { sphore_init(sem: &m_Sem); }
58 ~CSemaphore() { sphore_destroy(sem: &m_Sem); }
59 CSemaphore(const CSemaphore &) = delete;
60 int GetApproximateValue() { return m_Count.load(); }
61 void Wait()
62 {
63 sphore_wait(sem: &m_Sem);
64 m_Count.fetch_sub(i: 1);
65 }
66 void Signal()
67 {
68 m_Count.fetch_add(i: 1);
69 sphore_signal(sem: &m_Sem);
70 }
71};
72
73#endif
74