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)
18/**
19 * @ingroup Semaphore
20 */
21typedef void *SEMAPHORE;
22#elif defined(CONF_PLATFORM_MACOS)
23#include <semaphore.h>
24/**
25 * @ingroup Semaphore
26 */
27typedef sem_t *SEMAPHORE;
28#elif defined(CONF_FAMILY_UNIX)
29#include <semaphore.h>
30/**
31 * @ingroup Semaphore
32 */
33typedef sem_t SEMAPHORE;
34#else
35#error not implemented on this platform
36#endif
37
38/**
39 * @ingroup Semaphore
40 */
41void sphore_init(SEMAPHORE *sem);
42
43/**
44 * @ingroup Semaphore
45 */
46void sphore_wait(SEMAPHORE *sem);
47
48/**
49 * @ingroup Semaphore
50 */
51void sphore_signal(SEMAPHORE *sem);
52
53/**
54 * @ingroup Semaphore
55 */
56void sphore_destroy(SEMAPHORE *sem);
57
58/**
59 * @ingroup Semaphore
60 */
61class CSemaphore
62{
63 SEMAPHORE m_Sem;
64 // implement the counter separately, because the `sem_getvalue`-API is
65 // deprecated on macOS: https://stackoverflow.com/a/16655541
66 std::atomic_int m_Count{0};
67
68public:
69 CSemaphore() { sphore_init(sem: &m_Sem); }
70 ~CSemaphore() { sphore_destroy(sem: &m_Sem); }
71 CSemaphore(const CSemaphore &) = delete;
72 int GetApproximateValue() { return m_Count.load(); }
73 void Wait()
74 {
75 sphore_wait(sem: &m_Sem);
76 m_Count.fetch_sub(i: 1);
77 }
78 void Signal()
79 {
80 m_Count.fetch_add(i: 1);
81 sphore_signal(sem: &m_Sem);
82 }
83};
84
85#endif
86