Skip to content

Commit b1606ee

Browse files
committed
Implement Drop for FrameData
The types `Frame` and `FrameData` are mutually recursive, and the incidental linked lists that can be formed as a result can be long (at least in the order of thousands of elements). As a result, when a frame is deallocated, rust appears to recursively call `drop_in_place` down the list, causing stack overflows for long lists.
1 parent 82b4952 commit b1606ee

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

src/source/buffered.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::cmp;
2+
use std::mem;
23
use std::sync::{Arc, Mutex};
34
use std::time::Duration;
45

@@ -66,6 +67,40 @@ where
6667
next: Mutex<Arc<Frame<I>>>,
6768
}
6869

70+
impl<I> Drop for FrameData<I>
71+
where
72+
I: Source,
73+
I::Item: Sample,
74+
{
75+
fn drop(&mut self) {
76+
// This is necessary to prevent stack overflows deallocating long chains of the mutually
77+
// recursive `Frame` and `FrameData` types. This iteratively traverses as much of the
78+
// chain as needs to be deallocated, and repeatedly "pops" the head off the list. This
79+
// solves the problem, as when the time comes to actually deallocate the `FrameData`,
80+
// the `next` field will contain a `Frame::End`, or an `Arc` with additional references,
81+
// so the depth of recursive drops will be bounded.
82+
loop {
83+
if let Ok(arc_next) = self.next.get_mut() {
84+
if let Some(next_ref) = Arc::get_mut(arc_next) {
85+
// This allows us to own the next Frame.
86+
let next = mem::replace(next_ref, Frame::End);
87+
if let Frame::Data(next_data) = next {
88+
// Swap the current FrameData with the next one, allowing the current one
89+
// to go out of scope.
90+
*self = next_data;
91+
} else {
92+
break;
93+
}
94+
} else {
95+
break;
96+
}
97+
} else {
98+
break;
99+
}
100+
}
101+
}
102+
}
103+
69104
/// Builds a frame from the input iterator.
70105
fn extract<I>(mut input: I) -> Arc<Frame<I>>
71106
where

0 commit comments

Comments
 (0)