Skyward boardcore
Loading...
Searching...
No Matches
EventBroker.cpp
Go to the documentation of this file.
1/* Copyright (c) 2015-2018 Skyward Experimental Rocketry
2 * Authors: Luca Erbetta, Matteo Piazzolla
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "EventBroker.h"
24
26#include <utils/Debug.h>
27
28namespace Boardcore
29{
30
32
33void EventBroker::post(const Event& ev, uint8_t topic,
34 EventHandlerBase* subscriber)
35{
36#ifdef TRACE_EVENTS
37 LOG_DEBUG(logger, "Event: {}, Topic: {}", ev, topic);
38#endif
39
40 Lock<FastMutex> lock(mtxSubscribers);
41
42 if (subscribers.count(topic) > 0)
43 {
44 vector<EventHandlerBase*>& subs = subscribers.at(topic);
45 auto begin = subs.begin();
46 auto end = subs.end();
47
48 for (auto it = begin; it != end; it++)
49 {
50 // TODO: This may cause a deadlock if subscribe(...) in called in
51 // postEvent(...), but it should never happen anyway. What to do?
52
53 if ((*it) != subscriber)
54 (*it)->postEvent(ev);
55 }
56 }
57}
58
59uint16_t EventBroker::postDelayed(const Event& ev, uint8_t topic,
60 unsigned int delayMs)
61{
62 D(assert(delayMs >= EVENT_BROKER_MIN_DELAY &&
63 "delayMs must be longer or equal to EVENT_BROKER_MIN_DELAY"));
64
65 delayMs = std::max(delayMs, EVENT_BROKER_MIN_DELAY);
66
67 Lock<FastMutex> lock(mtxDelayedEvents);
68
69 // Delay in system ticks
70 long long delayTicks = static_cast<long long>(delayMs);
71
72 DelayedEvent dev{eventCounter++, ev, topic,
73 Kernel::getOldTick() + delayTicks};
74 bool added = false;
75
76 // Add the new event in the list, ordered by deadline (first = nearest
77 // deadline)
78 for (auto it = delayedEvents.begin(); it != delayedEvents.end(); it++)
79 {
80 if (dev.deadline < (*it).deadline)
81 {
82 delayedEvents.insert(it, dev);
83 added = true;
84 break;
85 }
86 }
87
88 if (!added) // In case this is the last/only event in the list
89 delayedEvents.push_back(dev);
90
91 return dev.schedId;
92}
93
95{
96 Lock<FastMutex> lock(mtxDelayedEvents);
97 for (auto it = delayedEvents.begin(); it != delayedEvents.end(); it++)
98 {
99 if ((*it).schedId == id)
100 {
101 delayedEvents.erase(it);
102 break;
103 }
104 }
105}
106
107void EventBroker::subscribe(EventHandlerBase* subscriber, uint8_t topic)
108{
109 Lock<FastMutex> lock(mtxSubscribers);
110 subscribers[topic].push_back(subscriber);
111}
112
113void EventBroker::unsubscribe(EventHandlerBase* subscriber, uint8_t topic)
114{
115 Lock<FastMutex> lock(mtxSubscribers);
116
117 deleteSubscriber(subscribers.at(topic), subscriber);
118}
119
121{
122 Lock<FastMutex> lock(mtxSubscribers);
123 for (auto it = subscribers.begin(); it != subscribers.end(); it++)
124 deleteSubscriber(it->second, subscriber);
125}
126
128{
129 Lock<FastMutex> lock(mtxDelayedEvents);
130 delayedEvents.clear();
131}
132
133// Posts delayed events with expired deadline
134void EventBroker::run()
135{
136 Lock<FastMutex> lock(mtxDelayedEvents);
137 while (!shouldStop())
138 {
139 while (delayedEvents.size() > 0 &&
140 delayedEvents.front().deadline <= Kernel::getOldTick())
141 {
142 // Pop the first element
143 DelayedEvent dev = delayedEvents.front();
144 delayedEvents.erase(delayedEvents.begin());
145
146 {
147 // Unlock the mutex to avoid a deadlock if someone calls
148 // postDelayed while receiving the event.
149 Unlock<FastMutex> unlock(lock);
150 post(dev.event, dev.topic);
151 }
152 }
153
154 // When to wakeup for the next cycle
155 long long sleepUntil = Kernel::getOldTick() + EVENT_BROKER_MIN_DELAY;
156
157 if (delayedEvents.size() > 0)
158 {
159 // If a deadline expires earlier, sleep until the deadline instead
160 if (delayedEvents.front().deadline < sleepUntil)
161 sleepUntil = delayedEvents.front().deadline;
162 }
163
164 {
165 // Unlock the mutex while sleeping
166 Unlock<FastMutex> unlock(lock);
168
169 Kernel::Thread::sleepUntil(sleepUntil);
170 }
171 }
172}
173
174void EventBroker::deleteSubscriber(vector<EventHandlerBase*>& subs,
175 EventHandlerBase* subscriber)
176{
177 auto it = subs.begin();
178
179 while (it != subs.end())
180 if (*it == subscriber)
181 it = subs.erase(it);
182 else
183 ++it;
184}
185
186} // namespace Boardcore
#define D(x)
Definition Debug.h:57
#define LOG_DEBUG(logger,...)
bool shouldStop()
Tells whether or not the ActiveObject should stop its execution.
void post(const Event &ev, uint8_t topic, EventHandlerBase *subscriber=nullptr)
uint16_t postDelayed(const Event &ev, uint8_t topic, unsigned int delayMs)
void subscribe(EventHandlerBase *subscriber, uint8_t topic)
void removeDelayed(uint16_t id)
void unsubscribe(EventHandlerBase *subscriber, uint8_t topic)
Unsubscribe an EventHandler from a specific topic This function should be used only for testing purpo...
EventBroker()
Construct a new Event Broker object.
void clearDelayedEvents()
Unschedules all pending events. This function should be used only for testing purposes.
static StackLogger & getInstance()
Definition Singleton.h:52
void sleepUntil(long long absoluteTimeMs)
Sleep until a given time in milliseconds.
Definition KernelTime.h:69
long long getOldTick()
Get the current time in milliseconds.
Definition KernelTime.h:43
This file includes all the types the logdecoder script will decode.
uint8_t Event
Definition Event.h:30
@ THID_EVT_BROKER
Definition StackData.h:39