-
Notifications
You must be signed in to change notification settings - Fork 0
/
semaphore.hpp
145 lines (113 loc) · 4.52 KB
/
semaphore.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#pragma once
#include "tickTimer.hpp"
#include "txCommon.hpp"
#include <functional>
namespace ThreadX
{
class CountingSemaphoreBase : protected Native::TX_SEMAPHORE
{
protected:
explicit CountingSemaphoreBase(const Ulong ceiling);
~CountingSemaphoreBase();
Error release(Ulong count);
private:
Ulong m_ceiling;
};
template <Ulong Ceiling = std::numeric_limits<Ulong>::max()> class CountingSemaphore : CountingSemaphoreBase
{
public:
using NotifyCallback = std::function<void(CountingSemaphore &)>;
// none copyable or movable
CountingSemaphore(const CountingSemaphore &) = delete;
CountingSemaphore &operator=(const CountingSemaphore &) = delete;
constexpr auto max() const;
explicit CountingSemaphore(
const std::string_view name, const Ulong initialCount = 0, const NotifyCallback &releaseNotifyCallback = {});
auto acquire();
// must be used for calls from initialization, timers, and ISRs
auto tryAcquire();
template <class Clock, typename Duration>
auto tryAcquireUntil(const std::chrono::time_point<Clock, Duration> &time);
/// retrieves an instance (a single count) from the specified counting semaphore.
/// As a result, the specified semaphore's count is decreased by one.
/// \param duration
template <typename Rep, typename Period> auto tryAcquireFor(const std::chrono::duration<Rep, Period> &duration);
/// puts an instance into the specified counting semaphore, which in reality increments the counting semaphore by
/// one. If the counting semaphore's current value is greater than or equal to the specified ceiling, the instance
/// will not be put and a TX_CEILING_EXCEEDED error will be returned.
/// \param count
auto release(const Ulong count = 1);
/// places the highest priority thread suspended for an instance of the semaphore at the front of the suspension
/// list. All other threads remain in the same FIFO order they were suspended in.
auto prioritise();
auto name() const;
auto count() const;
private:
static auto releaseNotifyCallback(auto notifySemaphorePtr);
const NotifyCallback m_releaseNotifyCallback;
};
template <Ulong Ceiling> constexpr auto CountingSemaphore<Ceiling>::max() const
{
return Ceiling;
}
/// Constructor
/// \param initialCount
/// \param releaseNotifyCallback The Notifycallback is not allowed to call any ThreadX API with a suspension option.
template <Ulong Ceiling>
CountingSemaphore<Ceiling>::CountingSemaphore(
const std::string_view name, const Ulong initialCount, const NotifyCallback &releaseNotifyCallback)
: CountingSemaphoreBase{Ceiling}, m_releaseNotifyCallback{releaseNotifyCallback}
{
assert(initialCount <= Ceiling);
using namespace Native;
[[maybe_unused]] Error error{tx_semaphore_create(this, const_cast<char *>(name.data()), initialCount)};
assert(error == Error::success);
if (releaseNotifyCallback)
{
error = Error{tx_semaphore_put_notify(this, CountingSemaphore::releaseNotifyCallback)};
assert(error == Error::success);
}
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::acquire()
{
return tryAcquireFor(TickTimer::waitForever);
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::tryAcquire()
{
return tryAcquireFor(TickTimer::noWait);
}
template <Ulong Ceiling>
template <class Clock, typename Duration>
auto CountingSemaphore<Ceiling>::tryAcquireUntil(const std::chrono::time_point<Clock, Duration> &time)
{
return tryAcquireFor(time - Clock::now());
}
template <Ulong Ceiling>
template <typename Rep, typename Period>
auto CountingSemaphore<Ceiling>::tryAcquireFor(const std::chrono::duration<Rep, Period> &duration)
{
return Error{tx_semaphore_get(this, TickTimer::ticks(duration))};
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::release(const Ulong count)
{
return CountingSemaphoreBase::release(count);
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::prioritise()
{
return Error{tx_semaphore_prioritize(this)};
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::name() const
{
return std::string_view{tx_semaphore_name};
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::count() const
{
return tx_semaphore_count;
}
template <Ulong Ceiling> auto CountingSemaphore<Ceiling>::releaseNotifyCallback(auto notifySemaphorePtr)
{
auto &semaphore{static_cast<CountingSemaphore &>(*notifySemaphorePtr)};
semaphore.m_releaseNotifyCallback(semaphore);
}
using BinarySemaphore = CountingSemaphore<1>;
} // namespace ThreadX