YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
wait_impl.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#include <cstddef>
12#include <iterator>
13#include <type_traits>
14
15namespace yaclib::detail {
16
18
19template <typename Event, typename Timeout, typename Range>
20bool WaitRange(Event& event, const Timeout& timeout, Range&& range, std::size_t count) noexcept {
21 const auto wait_count = [&] {
22 if constexpr (Event::kShared) {
23 return range([&, callback_count = std::size_t{}](auto handle) mutable noexcept {
24 if constexpr (std::is_same_v<UniqueHandle, decltype(handle)>) {
25 return handle.SetCallback(event.GetCall());
26 } else {
27 return handle.SetCallback(event.callbacks[callback_count++]);
28 }
29 });
30 } else {
31 return range([&](auto handle) noexcept {
32 return handle.SetCallback(event.GetCall());
33 });
34 }
35 }();
36
37 if (wait_count == 0 || event.SubEqual(count - wait_count + 1)) {
38 return true;
39 }
40
41 auto token = event.Make();
42 std::size_t reset_count = 0;
43
44 // Not available for shared future
45 // but this is not always if-constexpred away in case of shared futures
46 if constexpr (!std::is_same_v<Timeout, NoTimeoutTag>) {
47 // If you have problem with TSAN here, check this link: https://github.com/google/sanitizers/issues/1259
48 // TLDR: new pthread function is not supported by thread sanitizer yet.
49 if (event.Wait(token, timeout)) {
50 return true;
51 }
52 reset_count = range([](UniqueHandle handle) noexcept {
53 return handle.Reset();
54 });
55 if (reset_count != 0 && (reset_count == wait_count || event.SubEqual(reset_count))) {
56 return false;
57 }
58 // We know we have `wait_count - reset_count` Results, but we must wait until event was not used by cores
59 }
60 event.Wait(token);
61 return reset_count == 0; // LCOV_EXCL_LINE lcov won't parse it
62}
63
64template <typename Event, typename Timeout, typename... Handles>
65bool WaitCore(const Timeout& timeout, Handles... handles) noexcept {
66 static_assert(sizeof...(handles) >= 1, "Number of futures must be at least one");
67
68 static constexpr size_t kSharedCount = Count<SharedHandle, Handles...>;
69 static_assert(kSharedCount == 0 || std::is_same_v<Timeout, NoTimeoutTag>);
70
71 auto range = [&](auto&& func) noexcept {
72 return (... + static_cast<std::size_t>(func(handles)));
73 };
74
75 using CoreEvent = std::conditional_t<sizeof...(handles) == 1, MultiEvent<Event, OneCounter, CallCallback>,
77
78 // If we have only one shared handle, we can use .next of the original event
79 using FinalEvent = std::conditional_t<kSharedCount <= 1, CoreEvent, StaticSharedEvent<CoreEvent, kSharedCount>>;
80 FinalEvent event{sizeof...(handles) + 1};
81
82 return WaitRange(event, timeout, range, sizeof...(handles));
83}
84
85template <typename Event, typename Timeout, typename Iterator>
86bool WaitIterator(const Timeout& timeout, Iterator it, std::size_t count) noexcept {
88 "Wait function Iterator must be point to some Waitable (Future or SharedFuture)");
89 static constexpr bool kShared = std::is_same_v<decltype(it->GetHandle()), SharedHandle>;
90
91 if (count == 0) {
92 return true;
93 }
94
95 // TODO(ocelaiwo): We can try to unroll count more to avoid
96 // dynamic allocation in most common cases
97 if (count == 1) {
98 YACLIB_ASSERT(it->Valid());
99 return WaitCore<Event>(timeout, it->GetHandle());
100 }
101
102 auto range = [&](auto&& func) noexcept {
103 std::size_t wait_count = 0;
104 std::conditional_t<std::is_same_v<Timeout, NoTimeoutTag>, Iterator&, Iterator> range_it = it;
105 for (std::size_t i = 0; i != count; ++i) {
106 YACLIB_ASSERT(range_it->Valid());
107 wait_count += static_cast<std::size_t>(func(range_it->GetHandle()));
108 ++range_it;
109 }
110 return wait_count;
111 };
112
114 using FinalEvent = std::conditional_t<kShared, DynamicSharedEvent<CoreEvent>, CoreEvent>;
115 FinalEvent event{count + 1};
116
117 return WaitRange(event, timeout, range, count);
118}
119
122
123} // namespace yaclib::detail
#define YACLIB_ASSERT(cond)
Definition log.hpp:85
bool WaitRange(Event &event, const Timeout &timeout, Range &&range, std::size_t count) noexcept
Definition wait_impl.hpp:20
bool WaitCore(const Timeout &timeout, Handles... handles) noexcept
Definition wait_impl.hpp:65
template bool WaitCore< DefaultEvent, NoTimeoutTag, SharedHandle >(const NoTimeoutTag &, SharedHandle) noexcept
template bool WaitCore< DefaultEvent, NoTimeoutTag, UniqueHandle >(const NoTimeoutTag &, UniqueHandle) noexcept
bool WaitIterator(const Timeout &timeout, Iterator it, std::size_t count) noexcept
Definition wait_impl.hpp:86
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25