Skip to content

Commit e90e77f

Browse files
committed
feat engine: return FutureStatus from SingleConsumerEvent::WaitUntil
Breaking change: * @ref engine::SingleConsumerEvent::WaitUntil now returns @ref engine::FutureStatus instead of `bool`, allowing to distinguish failure reason precisely. commit_hash:14c9786711ae95baf432063ef2317df52c68b8ef
1 parent 68767e2 commit e90e77f

7 files changed

Lines changed: 25 additions & 22 deletions

File tree

core/include/userver/concurrent/mpsc_queue.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ bool MpscQueue<T>::DoPush(ProducerToken& /*unused*/, T&& value) {
223223
template <typename T>
224224
bool MpscQueue<T>::Pop(ConsumerToken& token, T& value, engine::Deadline deadline) {
225225
bool no_more_producers = false;
226-
const bool success = nonempty_event_.WaitUntil(deadline, [&] {
226+
const auto wait_status = nonempty_event_.WaitUntil(deadline, [&] {
227227
// kWeak is OK here, because if there is another push operation in process,
228228
// they will notify us after pushing.
229229
if (DoPop(token, value, impl::IntrusiveMpscQueueImpl::PopMode::kWeak)) {
@@ -240,7 +240,7 @@ bool MpscQueue<T>::Pop(ConsumerToken& token, T& value, engine::Deadline deadline
240240
}
241241
return false;
242242
});
243-
return success && !no_more_producers;
243+
return (wait_status == engine::FutureStatus::kReady) && !no_more_producers;
244244
}
245245

246246
template <typename T>

core/include/userver/concurrent/queue.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ class GenericQueue<T, QueuePolicy>::SingleProducerSide final {
418418
template <typename Token>
419419
[[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline, std::size_t value_size) {
420420
bool no_more_consumers = false;
421-
const bool success = non_full_event_.WaitUntil(deadline, [&] {
421+
const auto wait_status = non_full_event_.WaitUntil(deadline, [&] {
422422
if (queue_.NoMoreConsumers()) {
423423
no_more_consumers = true;
424424
return true;
@@ -428,7 +428,7 @@ class GenericQueue<T, QueuePolicy>::SingleProducerSide final {
428428
}
429429
return false;
430430
});
431-
return success && !no_more_consumers;
431+
return (wait_status == engine::FutureStatus::kReady) && !no_more_consumers;
432432
}
433433

434434
template <typename Token>
@@ -579,7 +579,7 @@ class GenericQueue<T, QueuePolicy>::SingleConsumerSide final {
579579
template <typename Token>
580580
[[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) {
581581
bool no_more_producers = false;
582-
const bool success = nonempty_event_.WaitUntil(deadline, [&] {
582+
const auto wait_status = nonempty_event_.WaitUntil(deadline, [&] {
583583
if (DoPop(token, value)) {
584584
return true;
585585
}
@@ -594,7 +594,7 @@ class GenericQueue<T, QueuePolicy>::SingleConsumerSide final {
594594
}
595595
return false;
596596
});
597-
return success && !no_more_producers;
597+
return (wait_status == engine::FutureStatus::kReady) && !no_more_producers;
598598
}
599599

600600
template <typename Token>

core/include/userver/engine/single_consumer_event.hpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,11 @@ class SingleConsumerEvent final {
8989
///
9090
/// Waiter side:
9191
/// @snippet engine/single_consumer_event_test.cpp CV waiter
92+
///
93+
/// @return `FutureStatus::kReady` if @a stop_waiting became `true`, `FutureStatus::kCancelled` if the current
94+
/// task was cancelled, `FutureStatus::kTimeout` if the deadline was reached.
9295
template <typename Predicate>
93-
[[nodiscard]] bool WaitUntil(Deadline, Predicate stop_waiting);
96+
[[nodiscard]] FutureStatus WaitUntil(Deadline, Predicate stop_waiting);
9497

9598
/// Resets the signal flag, if there is any existing event. Guarantees at least 'acquire' and 'release'
9699
/// memory ordering. Must only be called by the waiting task.
@@ -139,7 +142,7 @@ bool SingleConsumerEvent::WaitForEventUntil(std::chrono::time_point<Clock, Durat
139142
}
140143

141144
template <typename Predicate>
142-
bool SingleConsumerEvent::WaitUntil(Deadline deadline, Predicate stop_waiting) {
145+
FutureStatus SingleConsumerEvent::WaitUntil(Deadline deadline, Predicate stop_waiting) {
143146
// If the state, according to what we've been previously notified of via
144147
// 'Send', is OK, then return right away. Fresh state updates can also
145148
// leak to us here, but we should not rely on it.
@@ -151,8 +154,8 @@ bool SingleConsumerEvent::WaitUntil(Deadline deadline, Predicate stop_waiting) {
151154
// We may also receive false signals from cases when we are allowed
152155
// and unallowed to make progress in a rapid sequence, or when the notifier
153156
// thinks that we might be happy with the state, but we aren't.
154-
if (!WaitForEventUntil(deadline)) {
155-
return false;
157+
if (const auto status = WaitUntil(deadline); status != FutureStatus::kReady) {
158+
return status;
156159
}
157160

158161
if (!IsAutoReset()) {
@@ -163,7 +166,7 @@ bool SingleConsumerEvent::WaitUntil(Deadline deadline, Predicate stop_waiting) {
163166
}
164167
}
165168

166-
return true;
169+
return FutureStatus::kReady;
167170
}
168171

169172
} // namespace engine

core/src/engine/single_consumer_event_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,14 @@ UTEST_MT(SingleConsumerEvent, AsConditionVariable, 4) {
337337

338338
/// [CV waiter]
339339
std::uint64_t count_acquired{};
340-
const bool success = event.WaitUntil({}, [&] {
340+
const auto wait_status = event.WaitUntil({}, [&] {
341341
// Operations must be atomic, can be std::memory_order_relaxed.
342342
count_acquired = count.load(std::memory_order_relaxed);
343343
return count_acquired % 2 == 0 && count.compare_exchange_strong(count_acquired, 0, std::memory_order_relaxed);
344344
});
345345
/// [CV waiter]
346346

347-
EXPECT_TRUE(success);
347+
EXPECT_EQ(wait_status, engine::FutureStatus::kReady);
348348
EXPECT_TRUE(count_acquired != 0);
349349
EXPECT_TRUE(count_acquired % 2 == 0);
350350

core/src/engine/wait_all_checked.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,12 @@ FutureStatus WaitAllCheckedContext::Impl::WaitUntil(Deadline deadline) {
160160
}
161161
}
162162

163-
if (!result_ready_.WaitUntil(deadline, [this]() {
164-
return exception_source_index_.load(std::memory_order_relaxed) != kNoExceptionSource ||
165-
pending_notifications_.load(std::memory_order_relaxed) == 0;
166-
}))
167-
{
168-
return current_task::ShouldCancel() ? FutureStatus::kCancelled : FutureStatus::kTimeout;
163+
const auto wait_status = result_ready_.WaitUntil(deadline, [this] {
164+
return exception_source_index_.load(std::memory_order_relaxed) != kNoExceptionSource ||
165+
pending_notifications_.load(std::memory_order_relaxed) == 0;
166+
});
167+
if (wait_status != FutureStatus::kReady) {
168+
return wait_status;
169169
}
170170
auto exception_source_index = exception_source_index_.exchange(kNoExceptionSource, std::memory_order_relaxed);
171171
if (exception_source_index != kNoExceptionSource) {

core/src/server/net/listener_impl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void ListenerImpl::StopListening() {
8282
bool ListenerImpl::WaitForNoConnections(engine::Deadline deadline) const {
8383
return endpoint_info_->no_connections_event.WaitUntil(deadline, [this] {
8484
return endpoint_info_->connection_count == 0;
85-
});
85+
}) == engine::FutureStatus::kReady;
8686
}
8787

8888
void ListenerImpl::AcceptConnection(engine::io::Socket& request_socket, const PortConfig& port_config) {

core/src/utils/impl/wait_token_storage.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ void WaitTokenStorage::WaitForAllTokens() noexcept {
109109
}
110110

111111
const engine::TaskCancellationBlocker cancel_blocker;
112-
const bool wait_success = impl_.tokens_is_free_event.WaitUntil(engine::Deadline{}, [this] {
112+
const auto wait_status = impl_.tokens_is_free_event.WaitUntil(engine::Deadline{}, [this] {
113113
return impl_.tokens.IsFree();
114114
});
115-
UASSERT(wait_success);
115+
UASSERT(wait_status == engine::FutureStatus::kReady);
116116
}
117117

118118
void WaitTokenStorage::DoLock() {

0 commit comments

Comments
 (0)