blob: 1382332f06e8650b303c9f722d5185c7c4cc86da [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#ifndef AOS_EVENTS_EVENT_LOOP_TMPL_H_
2#define AOS_EVENTS_EVENT_LOOP_TMPL_H_
3
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cinttypes>
5#include <cstdint>
Alex Perrycb7da4b2019-08-28 19:35:56 -07006#include <type_traits>
Brian Silverman79ec7fc2020-06-08 20:11:22 -05007
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "aos/events/event_loop.h"
9#include "glog/logging.h"
10
11namespace aos {
Brian Silverman454bc112020-03-05 14:21:25 -080012namespace event_loop_internal {
Alex Perrycb7da4b2019-08-28 19:35:56 -070013
Brian Silverman454bc112020-03-05 14:21:25 -080014// From a watch functor, specializations of this will extract the message type
15// of the template argument. If T is not a valid message type, there will be no
16// matching specialization.
17//
18// This is just the forward declaration, which will be used by one of the
19// following specializations to match valid argument types.
Alex Perrycb7da4b2019-08-28 19:35:56 -070020template <class T>
Brian Silverman454bc112020-03-05 14:21:25 -080021struct watch_message_type_trait;
Alex Perrycb7da4b2019-08-28 19:35:56 -070022
23// From a watch functor, this will extract the message type of the argument.
24// This is the template specialization.
25template <class ClassType, class ReturnType, class A1>
26struct watch_message_type_trait<ReturnType (ClassType::*)(A1) const> {
27 using message_type = typename std::decay<A1>::type;
28};
29
Brian Silverman454bc112020-03-05 14:21:25 -080030} // namespace event_loop_internal
31
Alex Perrycb7da4b2019-08-28 19:35:56 -070032template <typename T>
33typename Sender<T>::Builder Sender<T>::MakeBuilder() {
Brian Silvermana1652f32020-01-29 20:41:44 -080034 return Builder(sender_.get(), sender_->fbb_allocator());
Alex Perrycb7da4b2019-08-28 19:35:56 -070035}
36
37template <typename Watch>
James Kuszmaul3ae42262019-11-08 12:33:41 -080038void EventLoop::MakeWatcher(const std::string_view channel_name, Watch &&w) {
Tyler Chatowb7c6eba2021-07-28 14:43:23 -070039 using MessageType =
40 typename event_loop_internal::watch_message_type_trait<decltype(
41 &Watch::operator())>::message_type;
Alex Perrycb7da4b2019-08-28 19:35:56 -070042 const Channel *channel = configuration::GetChannel(
Brian Silverman454bc112020-03-05 14:21:25 -080043 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
44 name(), node());
Alex Perrycb7da4b2019-08-28 19:35:56 -070045
46 CHECK(channel != nullptr)
47 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
Austin Schuhc59a1de2021-02-20 14:47:39 -080048 << MessageType::GetFullyQualifiedName()
49 << "\" } not found in config for application " << name() << ".";
Alex Perrycb7da4b2019-08-28 19:35:56 -070050
Brian Silverman454bc112020-03-05 14:21:25 -080051 MakeRawWatcher(channel,
52 [this, w](const Context &context, const void *message) {
53 context_ = context;
54 w(*flatbuffers::GetRoot<MessageType>(
55 reinterpret_cast<const char *>(message)));
56 });
57}
58
59template <typename MessageType>
60void EventLoop::MakeNoArgWatcher(const std::string_view channel_name,
61 std::function<void()> w) {
62 const Channel *channel = configuration::GetChannel(
63 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
64 name(), node());
65 CHECK(channel != nullptr)
66 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
Austin Schuhc59a1de2021-02-20 14:47:39 -080067 << MessageType::GetFullyQualifiedName()
68 << "\" } not found in config for application " << name() << ".";
Brian Silverman454bc112020-03-05 14:21:25 -080069 MakeRawNoArgWatcher(channel, [this, w](const Context &context) {
70 context_ = context;
71 w();
72 });
Alex Perrycb7da4b2019-08-28 19:35:56 -070073}
74
Austin Schuh39788ff2019-12-01 18:22:57 -080075inline bool RawFetcher::FetchNext() {
76 const auto result = DoFetchNext();
77 if (result.first) {
Brian Silvermanbf889922021-11-10 12:41:57 -080078 if (timing_.fetcher) {
79 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
80 }
Austin Schuh39788ff2019-12-01 18:22:57 -080081 const monotonic_clock::time_point monotonic_time = result.second;
Brian Silverman79ec7fc2020-06-08 20:11:22 -050082 ftrace_.FormatMessage(
83 "%.*s: fetch next: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
84 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
85 static_cast<int64_t>(monotonic_time.time_since_epoch().count()),
86 static_cast<int64_t>(
87 context_.monotonic_event_time.time_since_epoch().count()),
88 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -080089 const float latency =
90 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -080091 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080092 .count();
93 timing_.latency.Add(latency);
94 return true;
95 }
Brian Silverman79ec7fc2020-06-08 20:11:22 -050096 ftrace_.FormatMessage(
97 "%.*s: fetch next: still event=%" PRId64 " queue=%" PRIu32,
98 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
99 static_cast<int64_t>(
100 context_.monotonic_event_time.time_since_epoch().count()),
101 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800102 return false;
103}
104
105inline bool RawFetcher::Fetch() {
106 const auto result = DoFetch();
107 if (result.first) {
Brian Silvermanbf889922021-11-10 12:41:57 -0800108 if (timing_.fetcher) {
109 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
110 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800111 const monotonic_clock::time_point monotonic_time = result.second;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500112 ftrace_.FormatMessage(
113 "%.*s: fetch latest: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
114 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
115 static_cast<int64_t>(monotonic_time.time_since_epoch().count()),
116 static_cast<int64_t>(
117 context_.monotonic_event_time.time_since_epoch().count()),
118 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800119 const float latency =
120 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800121 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800122 .count();
123 timing_.latency.Add(latency);
124 return true;
125 }
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500126 ftrace_.FormatMessage(
127 "%.*s: fetch latest: still event=%" PRId64 " queue=%" PRIu32,
128 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
129 static_cast<int64_t>(
130 context_.monotonic_event_time.time_since_epoch().count()),
131 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800132 return false;
133}
134
milind1f1dca32021-07-03 13:50:07 -0700135inline RawSender::Error RawSender::Send(size_t size) {
Austin Schuhb5c6f972021-03-14 21:53:07 -0700136 return Send(size, monotonic_clock::min_time, realtime_clock::min_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700137 0xffffffffu, event_loop_->boot_uuid());
Austin Schuhb5c6f972021-03-14 21:53:07 -0700138}
139
milind1f1dca32021-07-03 13:50:07 -0700140inline RawSender::Error RawSender::Send(
Austin Schuhad154822019-12-27 15:45:13 -0800141 size_t size, aos::monotonic_clock::time_point monotonic_remote_time,
142 aos::realtime_clock::time_point realtime_remote_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700143 uint32_t remote_queue_index, const UUID &uuid) {
milind1f1dca32021-07-03 13:50:07 -0700144 const auto err = DoSend(size, monotonic_remote_time, realtime_remote_time,
145 remote_queue_index, uuid);
James Kuszmaul78514332022-04-06 15:08:34 -0700146 switch (err) {
147 case Error::kOk: {
148 if (timing_.sender) {
149 timing_.size.Add(size);
150 timing_.sender->mutate_count(timing_.sender->count() + 1);
151 }
152 ftrace_.FormatMessage(
153 "%.*s: sent internal: event=%" PRId64 " queue=%" PRIu32,
154 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
155 static_cast<int64_t>(
156 monotonic_sent_time().time_since_epoch().count()),
157 sent_queue_index());
158 break;
Brian Silvermanbf889922021-11-10 12:41:57 -0800159 }
James Kuszmaul78514332022-04-06 15:08:34 -0700160 case Error::kMessagesSentTooFast:
161 timing_.IncrementError(timing::SendError::MESSAGE_SENT_TOO_FAST);
162 break;
163 case Error::kInvalidRedzone:
164 timing_.IncrementError(timing::SendError::INVALID_REDZONE);
165 break;
Austin Schuh39788ff2019-12-01 18:22:57 -0800166 }
milind1f1dca32021-07-03 13:50:07 -0700167 return err;
Austin Schuh39788ff2019-12-01 18:22:57 -0800168}
169
milind1f1dca32021-07-03 13:50:07 -0700170inline RawSender::Error RawSender::Send(const void *data, size_t size) {
Austin Schuhb5c6f972021-03-14 21:53:07 -0700171 return Send(data, size, monotonic_clock::min_time, realtime_clock::min_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700172 0xffffffffu, event_loop_->boot_uuid());
Austin Schuhb5c6f972021-03-14 21:53:07 -0700173}
174
milind1f1dca32021-07-03 13:50:07 -0700175inline RawSender::Error RawSender::Send(
Austin Schuhad154822019-12-27 15:45:13 -0800176 const void *data, size_t size,
177 aos::monotonic_clock::time_point monotonic_remote_time,
178 aos::realtime_clock::time_point realtime_remote_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700179 uint32_t remote_queue_index, const UUID &uuid) {
milind1f1dca32021-07-03 13:50:07 -0700180 const auto err = DoSend(data, size, monotonic_remote_time,
181 realtime_remote_time, remote_queue_index, uuid);
182 if (err == RawSender::Error::kOk) {
Brian Silvermanbf889922021-11-10 12:41:57 -0800183 if (timing_.sender) {
184 timing_.size.Add(size);
185 timing_.sender->mutate_count(timing_.sender->count() + 1);
186 }
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500187 ftrace_.FormatMessage(
188 "%.*s: sent external: event=%" PRId64 " queue=%" PRIu32,
189 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
190 static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
191 sent_queue_index());
Austin Schuh39788ff2019-12-01 18:22:57 -0800192 }
milind1f1dca32021-07-03 13:50:07 -0700193 return err;
Austin Schuh39788ff2019-12-01 18:22:57 -0800194}
195
milind1f1dca32021-07-03 13:50:07 -0700196inline RawSender::Error RawSender::Send(const SharedSpan data) {
Tyler Chatowb7c6eba2021-07-28 14:43:23 -0700197 return Send(std::move(data), monotonic_clock::min_time,
198 realtime_clock::min_time, 0xffffffffu, event_loop_->boot_uuid());
199}
200
milind1f1dca32021-07-03 13:50:07 -0700201inline RawSender::Error RawSender::Send(
Tyler Chatowb7c6eba2021-07-28 14:43:23 -0700202 const SharedSpan data,
203 aos::monotonic_clock::time_point monotonic_remote_time,
204 aos::realtime_clock::time_point realtime_remote_time,
205 uint32_t remote_queue_index, const UUID &uuid) {
206 const size_t size = data->size();
milind1f1dca32021-07-03 13:50:07 -0700207 const auto err = DoSend(std::move(data), monotonic_remote_time,
208 realtime_remote_time, remote_queue_index, uuid);
209 if (err == Error::kOk) {
Brian Silvermanbf889922021-11-10 12:41:57 -0800210 if (timing_.sender) {
211 timing_.size.Add(size);
212 timing_.sender->mutate_count(timing_.sender->count() + 1);
213 }
Tyler Chatowb7c6eba2021-07-28 14:43:23 -0700214 ftrace_.FormatMessage(
215 "%.*s: sent shared: event=%" PRId64 " queue=%" PRIu32,
216 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
217 static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
218 sent_queue_index());
Tyler Chatowb7c6eba2021-07-28 14:43:23 -0700219 }
milind1f1dca32021-07-03 13:50:07 -0700220 return err;
Tyler Chatowb7c6eba2021-07-28 14:43:23 -0700221}
222
Austin Schuhcde39fd2020-02-22 20:58:24 -0800223inline monotonic_clock::time_point TimerHandler::Call(
Austin Schuh39788ff2019-12-01 18:22:57 -0800224 std::function<monotonic_clock::time_point()> get_time,
225 monotonic_clock::time_point event_time) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800226 const monotonic_clock::time_point monotonic_start_time = get_time();
227
Austin Schuha9012be2021-07-21 15:19:11 -0700228 event_loop_->SetTimerContext(event_time);
Austin Schuh39788ff2019-12-01 18:22:57 -0800229
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500230 ftrace_.FormatMessage(
231 "timer: %.*s: start now=%" PRId64 " event=%" PRId64,
232 static_cast<int>(name_.size()), name_.data(),
233 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
234 static_cast<int64_t>(event_time.time_since_epoch().count()));
Brian Silvermanbf889922021-11-10 12:41:57 -0800235 if (timing_.timer) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800236 const float start_latency =
237 std::chrono::duration_cast<std::chrono::duration<float>>(
238 monotonic_start_time - event_time)
239 .count();
240 timing_.wakeup_latency.Add(start_latency);
Brian Silvermanbf889922021-11-10 12:41:57 -0800241 timing_.timer->mutate_count(timing_.timer->count() + 1);
Austin Schuh39788ff2019-12-01 18:22:57 -0800242 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800243 fn_();
244
245 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500246 ftrace_.FormatMessage(
247 "timer: %.*s: end now=%" PRId64, static_cast<int>(name_.size()),
248 name_.data(),
249 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800250
251 const float handler_latency =
252 std::chrono::duration_cast<std::chrono::duration<float>>(
253 monotonic_end_time - monotonic_start_time)
254 .count();
255 timing_.handler_time.Add(handler_latency);
Austin Schuhcde39fd2020-02-22 20:58:24 -0800256 return monotonic_start_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800257}
258
259inline void PhasedLoopHandler::Call(
260 std::function<monotonic_clock::time_point()> get_time,
261 std::function<void(monotonic_clock::time_point)> schedule) {
262 // Read time directly to save a vtable indirection...
263 const monotonic_clock::time_point monotonic_start_time = get_time();
264
265 // Update the context to hold the desired wakeup time.
Austin Schuha9012be2021-07-21 15:19:11 -0700266 event_loop_->SetTimerContext(phased_loop_.sleep_time());
Austin Schuh39788ff2019-12-01 18:22:57 -0800267
Milind Upadhyay42589bb2021-05-19 20:05:16 -0700268 // Compute how many cycles elapsed
269 cycles_elapsed_ += phased_loop_.Iterate(monotonic_start_time);
Austin Schuh39788ff2019-12-01 18:22:57 -0800270
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500271 ftrace_.FormatMessage(
272 "phased: %.*s: start now=%" PRId64 " event=%" PRId64 " cycles=%d",
273 static_cast<int>(name_.size()), name_.data(),
274 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
275 static_cast<int64_t>(
276 phased_loop_.sleep_time().time_since_epoch().count()),
277 cycles_elapsed_);
Brian Silvermanbf889922021-11-10 12:41:57 -0800278 if (timing_.timer) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800279 const float start_latency =
280 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800281 monotonic_start_time - event_loop_->context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800282 .count();
283 timing_.wakeup_latency.Add(start_latency);
Brian Silvermanbf889922021-11-10 12:41:57 -0800284 timing_.timer->mutate_count(timing_.timer->count() + 1);
Austin Schuh39788ff2019-12-01 18:22:57 -0800285 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800286
287 // Call the function with the elapsed cycles.
288 fn_(cycles_elapsed_);
289 cycles_elapsed_ = 0;
290
Milind Upadhyay42589bb2021-05-19 20:05:16 -0700291 // Schedule the next wakeup.
292 schedule(phased_loop_.sleep_time());
293
Austin Schuh39788ff2019-12-01 18:22:57 -0800294 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500295 ftrace_.FormatMessage(
296 "phased: %.*s: end now=%" PRId64, static_cast<int>(name_.size()),
297 name_.data(),
298 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800299
300 const float handler_latency =
301 std::chrono::duration_cast<std::chrono::duration<float>>(
302 monotonic_end_time - monotonic_start_time)
303 .count();
304 timing_.handler_time.Add(handler_latency);
305
Brian Silvermanaf9a4d82020-10-06 15:10:58 -0700306 // If the handler took too long so we blew by the previous deadline, we
Austin Schuh91ba6392020-10-03 13:27:47 -0700307 // want to just try for the next deadline. Reschedule.
Austin Schuh39788ff2019-12-01 18:22:57 -0800308 if (monotonic_end_time > phased_loop_.sleep_time()) {
309 Reschedule(schedule, monotonic_end_time);
310 }
311}
312
313// Class to automate the timing report generation for watchers.
314class WatcherState {
315 public:
316 WatcherState(
317 EventLoop *event_loop, const Channel *channel,
318 std::function<void(const Context &context, const void *message)> fn)
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500319 : channel_index_(event_loop->ChannelIndex(channel)),
320 ftrace_prefix_(configuration::StrippedChannelToString(channel)),
321 fn_(std::move(fn)) {}
Austin Schuh39788ff2019-12-01 18:22:57 -0800322
323 virtual ~WatcherState() {}
324
325 // Calls the callback, measuring time with get_time, with the provided
326 // context.
327 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
Austin Schuhc5dc98f2021-06-16 14:52:46 -0700328 Context context) noexcept {
Brian Silverman6b8a3c32020-03-06 11:26:14 -0800329 if (context.data) {
330 CheckChannelDataAlignment(context.data, context.size);
331 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800332 const monotonic_clock::time_point monotonic_start_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500333 ftrace_.FormatMessage(
334 "%.*s: watcher start: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
335 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
336 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
337 static_cast<int64_t>(
338 context.monotonic_event_time.time_since_epoch().count()),
339 context.queue_index);
Brian Silvermanbf889922021-11-10 12:41:57 -0800340 if (watcher_) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800341 const float start_latency =
342 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800343 monotonic_start_time - context.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800344 .count();
345 wakeup_latency_.Add(start_latency);
Brian Silvermanbf889922021-11-10 12:41:57 -0800346 watcher_->mutate_count(watcher_->count() + 1);
Austin Schuh39788ff2019-12-01 18:22:57 -0800347 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800348 fn_(context, context.data);
349
350 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500351 ftrace_.FormatMessage(
352 "%.*s: watcher end: now=%" PRId64,
353 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
354 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800355
356 const float handler_latency =
357 std::chrono::duration_cast<std::chrono::duration<float>>(
358 monotonic_end_time - monotonic_start_time)
359 .count();
360 handler_time_.Add(handler_latency);
361 }
362
363 int channel_index() const { return channel_index_; }
364
365 void set_timing_report(timing::Watcher *watcher);
366 void ResetReport();
367
368 virtual void Startup(EventLoop *event_loop) = 0;
369
370 protected:
371 const int channel_index_;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500372 const std::string ftrace_prefix_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800373
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500374 const std::function<void(const Context &context, const void *message)> fn_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800375
376 internal::TimingStatistic wakeup_latency_;
377 internal::TimingStatistic handler_time_;
378 timing::Watcher *watcher_ = nullptr;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500379
380 Ftrace ftrace_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800381};
382
Austin Schuha28cbc32019-12-27 16:28:04 -0800383template <typename T>
milind1f1dca32021-07-03 13:50:07 -0700384RawSender::Error Sender<T>::Send(
385 const NonSizePrefixedFlatbuffer<T> &flatbuffer) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800386 return sender_->Send(flatbuffer.span().data(), flatbuffer.span().size());
Austin Schuha28cbc32019-12-27 16:28:04 -0800387}
388
Brian Silverman341b57e2020-06-23 16:23:18 -0700389template <typename T>
milind1f1dca32021-07-03 13:50:07 -0700390RawSender::Error Sender<T>::SendDetached(FlatbufferDetachedBuffer<T> detached) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800391 CHECK_EQ(static_cast<void *>(detached.span().data() + detached.span().size() -
392 sender_->size()),
393 sender_->data())
Brian Silverman341b57e2020-06-23 16:23:18 -0700394 << ": May only send the buffer detached from this Sender";
Austin Schuhadd6eb32020-11-09 21:24:26 -0800395 return sender_->Send(detached.span().size());
Brian Silverman341b57e2020-06-23 16:23:18 -0700396}
397
Alex Perrycb7da4b2019-08-28 19:35:56 -0700398} // namespace aos
399
400#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H