Skip to content

Commit 806ecaa

Browse files
authored
Implement Drop for FrameData (#285)
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 2c171d6 commit 806ecaa

1 file changed

Lines changed: 35 additions & 0 deletions

File tree

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

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

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

0 commit comments

Comments
 (0)