Exchange promise for condition_variable when flushing (fixes #3221) (#3228)

std::promise and std::future use std::call_once under the hood, which requires
the tls-model to be at least initial_exec, excluding local_exec.

Furthermore, gcc has a bug regarding exceptions in std::call_once that
is best avoided. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66146
for more info.

Signed-off-by: Michael de Lang <kingoipo@gmail.com>
This commit is contained in:
Michael de Lang
2024-10-28 21:38:01 +01:00
committed by GitHub
parent ee16895787
commit 16e0d2e77c
3 changed files with 65 additions and 44 deletions

View File

@@ -62,13 +62,25 @@ void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr,
post_async_msg_(std::move(async_m), overflow_policy);
}
std::future<void> SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr,
void SPDLOG_INLINE thread_pool::post_and_wait_for_flush(async_logger_ptr &&worker_ptr,
async_overflow_policy overflow_policy) {
std::promise<void> promise;
std::future<void> future = promise.get_future();
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush, std::move(promise)),
overflow_policy);
return future;
std::mutex m;
std::unique_lock<std::mutex> l(m);
std::condition_variable cv;
std::atomic<async_msg_flush> cv_flag{async_msg_flush::not_synced};
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush, [&cv, &cv_flag](async_msg_flush flushed) {
cv_flag.store(flushed, std::memory_order_relaxed);
cv.notify_all();
}), overflow_policy);
while(cv_flag.load(std::memory_order_relaxed) == async_msg_flush::not_synced) {
cv.wait_for(l, std::chrono::milliseconds(100), [&cv_flag]() {
return cv_flag.load(std::memory_order_relaxed) != async_msg_flush::not_synced;
});
}
if(cv_flag.load(std::memory_order_relaxed) == async_msg_flush::synced_not_flushed) {
throw spdlog_ex("Request for flushing got dropped.");
}
}
size_t SPDLOG_INLINE thread_pool::overrun_counter() { return q_.overrun_counter(); }
@@ -112,7 +124,10 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_() {
}
case async_msg_type::flush: {
incoming_async_msg.worker_ptr->backend_flush_();
incoming_async_msg.flush_promise.set_value();
if(incoming_async_msg.flush_callback) {
incoming_async_msg.flush_callback(async_msg_flush::synced_flushed);
incoming_async_msg.flush_callback = nullptr;
}
return true;
}