Skip to content

Commit 049c638

Browse files
committed
Destroy the thread pool before the final flush if tearing down
1 parent 586591c commit 049c638

File tree

3 files changed

+39
-20
lines changed

3 files changed

+39
-20
lines changed

spdlog/src/sink/async_sink/async_pool_sink.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,12 @@ impl Sink for AsyncPoolSink {
8181
if crate::IS_TEARING_DOWN.load(Ordering::SeqCst) {
8282
// https://github.com/SpriteOvO/spdlog-rs/issues/64
8383
//
84-
// `crossbeam` uses thread-local internally, which is not supported in `atexit`
85-
// callback. Let's directly flush the sinks on the current thread if the program
86-
// is tearing down.
84+
// If the program is tearing down, this will be the final flush. `crossbeam`
85+
// uses thread-local internally, which is not supported in `atexit` callback.
86+
// This can be bypassed by flushing sinks directly on the current thread, but
87+
// before we do that we have to destroy the thread pool to ensure that any
88+
// pending log tasks are completed.
89+
self.thread_pool.destroy();
8790
self.backend.flush()
8891
} else {
8992
self.assign_task(Task::Flush {

spdlog/src/thread_pool.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ use crate::{
3131
/// ```
3232
///
3333
/// [`AsyncPoolSink`]: crate::sink::AsyncPoolSink
34-
pub struct ThreadPool {
34+
pub struct ThreadPool(ArcSwapOption<ThreadPoolInner>);
35+
36+
struct ThreadPoolInner {
3537
threads: Vec<Option<JoinHandle<()>>>,
3638
sender: Option<Sender<Task>>,
3739
}
@@ -68,7 +70,8 @@ impl ThreadPool {
6870
}
6971

7072
pub(super) fn assign_task(&self, task: Task, overflow_policy: OverflowPolicy) -> Result<()> {
71-
let sender = self.sender.as_ref().unwrap();
73+
let inner = self.0.load();
74+
let sender = inner.as_ref().unwrap().sender.as_ref().unwrap();
7275

7376
match overflow_policy {
7477
OverflowPolicy::Block => sender.send(task).map_err(Error::from_crossbeam_send),
@@ -77,21 +80,28 @@ impl ThreadPool {
7780
.map_err(Error::from_crossbeam_try_send),
7881
}
7982
}
83+
84+
pub(super) fn destroy(&self) {
85+
if let Some(mut inner) = self.0.swap(None) {
86+
// Or use `Arc::into_inner`, but it requires us to bump MSRV.
87+
let inner = Arc::get_mut(&mut inner).unwrap();
88+
89+
// drop our sender, threads will break the loop after receiving and processing
90+
// the remaining tasks
91+
inner.sender.take();
92+
93+
for thread in &mut inner.threads {
94+
if let Some(thread) = thread.take() {
95+
thread.join().expect("failed to join a thread from pool");
96+
}
97+
}
98+
}
99+
}
80100
}
81101

82102
impl Drop for ThreadPool {
83103
fn drop(&mut self) {
84-
// drop our sender, threads will break the loop after receiving and processing
85-
// the remaining tasks
86-
self.sender.take();
87-
88-
for thread in &mut self.threads {
89-
thread
90-
.take()
91-
.unwrap()
92-
.join()
93-
.expect("failed to join a thread from pool");
94-
}
104+
self.destroy();
95105
}
96106
}
97107

@@ -179,10 +189,12 @@ impl ThreadPoolBuilder {
179189
}))
180190
});
181191

182-
Ok(ThreadPool {
183-
threads,
184-
sender: Some(sender),
185-
})
192+
Ok(ThreadPool(ArcSwapOption::new(Some(Arc::new(
193+
ThreadPoolInner {
194+
threads,
195+
sender: Some(sender),
196+
},
197+
)))))
186198
}
187199
}
188200

spdlog/tests/global_async_pool_sink.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@ use spdlog::{
1616
ErrorHandler,
1717
};
1818

19+
static IS_LOGGED: AtomicBool = AtomicBool::new(false);
1920
static IS_FLUSHED: AtomicBool = AtomicBool::new(false);
2021

2122
struct SetFlagSink;
2223

2324
impl Sink for SetFlagSink {
2425
fn log(&self, _record: &spdlog::Record) -> error::Result<()> {
26+
IS_LOGGED.store(true, Ordering::SeqCst);
2527
Ok(())
2628
}
2729

2830
fn flush(&self) -> error::Result<()> {
31+
// Assert that the record has been logged before flushing
32+
assert!(IS_LOGGED.load(Ordering::SeqCst));
2933
IS_FLUSHED.store(true, Ordering::SeqCst);
3034
Ok(())
3135
}

0 commit comments

Comments
 (0)