use super::mux_task::tcp_write_probe;
use crate::core::context::ffmpeg_context::FfmpegContext;
use crate::core::context::input::Input;
use crate::core::context::output::Output;
use crate::core::packet_sink::PacketSink;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
fn require_write_parked(deadline: Instant) -> Result<u64, String> {
let mut prev: Option<(u64, u64)> = None;
let mut stable = 0u32;
loop {
std::thread::sleep(Duration::from_millis(250));
let returned = tcp_write_probe::RETURNED.load(Ordering::Acquire);
let entered = tcp_write_probe::ENTERED.load(Ordering::Acquire);
if entered == returned + 1 && prev == Some((entered, returned)) {
stable += 1;
if stable >= 6 {
if tcp_write_probe::RETURNED.load(Ordering::Acquire) == returned {
return Ok(entered);
}
stable = 0;
}
} else {
stable = 0;
}
prev = Some((entered, returned));
if Instant::now() >= deadline {
return Err(format!(
"the muxer is not parked inside a tcp write \
(entered {entered}, returned {returned})"
));
}
}
}
fn queued_bytes(stream: &std::net::TcpStream, buf: &mut [u8]) -> usize {
match stream.peek(buf) {
Ok(n) => n,
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => 0,
Err(e) => panic!("peek on the unread peer failed: {e}"),
}
}
fn wait_for_receive_queue_plateau(
stream: &std::net::TcpStream,
peek_buf: &mut Vec<u8>,
deadline: Instant,
) -> Result<usize, String> {
let mut queued_prev = 0usize;
let mut stable_polls = 0u32;
loop {
std::thread::sleep(Duration::from_millis(250));
if Instant::now() >= deadline {
return Err(format!(
"the unread peer's receive queue never reached a plateau \
(last observed {queued_prev} bytes)"
));
}
let queued = queued_bytes(stream, peek_buf);
if queued == peek_buf.len() {
*peek_buf = vec![0u8; peek_buf.len() * 2];
stable_polls = 0;
queued_prev = 0;
continue;
}
if queued > 0 && queued == queued_prev {
stable_polls += 1;
if stable_polls >= 6 {
return Ok(queued);
}
} else {
stable_polls = 0;
queued_prev = queued;
}
}
}
fn prove_post_plateau_refill(
stream: &std::net::TcpStream,
peek_buf: &mut [u8],
pinned: usize,
deadline: Instant,
) -> Result<usize, String> {
const RESIDUE_BOUND: usize = 64 * 1024;
let mut drained_total = 0usize;
loop {
let queued = queued_bytes(stream, peek_buf);
if (queued + drained_total).saturating_sub(pinned) > RESIDUE_BOUND {
return Ok(drained_total);
}
if Instant::now() >= deadline {
return Err(
"the receive queue never refilled after a drain: the sibling was \
not blocked on flow control (writer idle or stalled upstream)"
.into(),
);
}
if queued > 0 {
let take = (queued / 2).max(1);
let n = std::io::Read::read(&mut (&*stream), &mut peek_buf[..take])
.map_err(|e| format!("draining the pinned receive queue: {e}"))?;
drained_total += n;
}
std::thread::sleep(Duration::from_millis(25));
}
}
fn require_flow_control_repin(
stream: &std::net::TcpStream,
peek_buf: &mut Vec<u8>,
deadline: Instant,
) -> Result<usize, String> {
wait_for_receive_queue_plateau(stream, peek_buf, deadline)
.map_err(|e| format!("no second plateau after the refill: {e}"))
}
#[cfg(target_os = "linux")]
fn listener_with_small_rcvbuf(rcvbuf: libc::c_int) -> Option<std::net::TcpListener> {
use std::os::unix::io::FromRawFd;
unsafe {
let fd = libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0);
if fd < 0 {
return None;
}
let set = |opt: libc::c_int, val: libc::c_int| -> bool {
libc::setsockopt(
fd,
libc::SOL_SOCKET,
opt,
&val as *const libc::c_int as *const libc::c_void,
std::mem::size_of::<libc::c_int>() as libc::socklen_t,
) == 0
};
if !set(libc::SO_RCVBUF, rcvbuf) || !set(libc::SO_REUSEADDR, 1) {
libc::close(fd);
return None;
}
let mut addr: libc::sockaddr_in = std::mem::zeroed();
addr.sin_family = libc::AF_INET as libc::sa_family_t;
addr.sin_port = 0; addr.sin_addr.s_addr = u32::from(std::net::Ipv4Addr::LOCALHOST).to_be();
let bound = libc::bind(
fd,
&addr as *const libc::sockaddr_in as *const libc::sockaddr,
std::mem::size_of::<libc::sockaddr_in>() as libc::socklen_t,
) == 0;
if !bound || libc::listen(fd, 1) != 0 {
libc::close(fd);
return None;
}
Some(std::net::TcpListener::from_raw_fd(fd))
}
}
fn make_backpressure_listener() -> (std::net::TcpListener, bool) {
#[cfg(target_os = "linux")]
{
if let Some(l) = listener_with_small_rcvbuf(16 * 1024) {
return (l, true);
}
}
(std::net::TcpListener::bind("127.0.0.1:0").unwrap(), false)
}
#[cfg(unix)]
fn pin_peer_rcvbuf(stream: &std::net::TcpStream) {
use std::os::unix::io::AsRawFd;
let fd = stream.as_raw_fd();
unsafe {
let mut inherited: libc::c_int = 0;
let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
libc::getsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_RCVBUF,
&mut inherited as *mut libc::c_int as *mut libc::c_void,
&mut len,
);
#[cfg(target_os = "linux")]
let set_rc = {
let val: libc::c_int = 16 * 1024;
libc::setsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_RCVBUF,
&val as *const libc::c_int as *const libc::c_void,
std::mem::size_of::<libc::c_int>() as libc::socklen_t,
)
};
#[cfg(not(target_os = "linux"))]
let set_rc: libc::c_int = -1;
let mut effective: libc::c_int = 0;
let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
libc::getsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_RCVBUF,
&mut effective as *mut libc::c_int as *mut libc::c_void,
&mut len,
);
eprintln!(
"wedge peer rcvbuf: inherited={inherited} set_rc={set_rc} effective={effective}"
);
}
}
#[cfg(not(unix))]
fn pin_peer_rcvbuf(_stream: &std::net::TcpStream) {}
#[cfg(unix)]
fn peer_socket_stats(stream: &std::net::TcpStream) -> (libc::c_int, libc::c_int) {
use std::os::unix::io::AsRawFd;
let fd = stream.as_raw_fd();
unsafe {
let mut rcvbuf: libc::c_int = -1;
let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
libc::getsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_RCVBUF,
&mut rcvbuf as *mut libc::c_int as *mut libc::c_void,
&mut len,
);
let mut unread: libc::c_int = -1;
libc::ioctl(fd, libc::FIONREAD, &mut unread);
(rcvbuf, unread)
}
}
#[cfg(not(unix))]
fn peer_socket_stats(_stream: &std::net::TcpStream) -> (i32, i32) {
(-1, -1)
}
#[cfg(target_os = "macos")]
fn receive_autotune_uncapped() -> bool {
let name = std::ffi::CString::new("net.inet.tcp.autorcvbufmax").unwrap();
let mut val: libc::c_int = 0;
let mut len: libc::size_t = std::mem::size_of::<libc::c_int>();
let rc = unsafe {
libc::sysctlbyname(
name.as_ptr(),
&mut val as *mut libc::c_int as *mut libc::c_void,
&mut len,
std::ptr::null_mut(),
0,
)
};
rc != 0 || val > 256 * 1024
}
#[cfg(not(target_os = "macos"))]
fn receive_autotune_uncapped() -> bool {
false
}
#[test]
fn flow_control_repin_rejects_a_writer_that_stalls_after_the_refill() {
let _serial = tcp_write_probe::exclusive();
let (listener, _rcvbuf_shrunk) = make_backpressure_listener();
let addr = listener.local_addr().unwrap();
let (stream_tx, stream_rx) = std::sync::mpsc::channel();
let accept_thread = std::thread::spawn(move || {
if let Ok((stream, _)) = listener.accept() {
let _ = stream_tx.send(stream);
}
});
let stop_writing = Arc::new(AtomicBool::new(false));
let stop_flag = stop_writing.clone();
let writer_thread = std::thread::spawn(move || {
let mut peer = std::net::TcpStream::connect(addr).expect("writer connect");
let chunk = [0u8; 8 * 1024];
while !stop_flag.load(Ordering::Acquire) {
if std::io::Write::write_all(&mut peer, &chunk).is_err() {
break;
}
}
});
let stream = stream_rx
.recv_timeout(Duration::from_secs(10))
.expect("the synthetic writer never connected");
stream.set_nonblocking(true).unwrap();
let mut peek_buf = vec![0u8; 4 * 1024 * 1024];
let pinned = wait_for_receive_queue_plateau(
&stream,
&mut peek_buf,
Instant::now() + Duration::from_secs(20),
)
.expect("the synthetic writer must reach a first plateau");
prove_post_plateau_refill(
&stream,
&mut peek_buf,
pinned,
Instant::now() + Duration::from_secs(15),
)
.expect("a live writer must pass stage 2 — the confounder is what comes next");
stop_writing.store(true, Ordering::Release);
let drain_deadline = Instant::now() + Duration::from_secs(10);
let mut writer_gone = false;
let mut empty_since: Option<Instant> = None;
loop {
assert!(
Instant::now() < drain_deadline,
"the synthetic writer's residue never drained"
);
if !writer_gone && writer_thread.is_finished() {
writer_gone = true;
}
let queued = queued_bytes(&stream, &mut peek_buf);
if queued > 0 {
let _ = std::io::Read::read(&mut (&stream), &mut peek_buf[..queued])
.expect("draining the dead writer's residue");
empty_since = None;
} else if writer_gone {
let since = *empty_since.get_or_insert_with(Instant::now);
if since.elapsed() >= Duration::from_millis(500) {
break;
}
}
std::thread::sleep(Duration::from_millis(20));
}
writer_thread.join().expect("the synthetic writer panicked");
let verdict = require_flow_control_repin(
&stream,
&mut peek_buf,
Instant::now() + Duration::from_secs(5),
);
let rejection = verdict.expect_err(
"stage 3 accepted a stalled producer: the repin proves nothing and \
the finalize-gating probe would run against an unblocked sibling",
);
assert!(
rejection.contains("no second plateau"),
"the rejection must name the missing repin, got: {rejection}"
);
drop(stream);
let _ = accept_thread.join();
}
#[test]
fn write_parked_probe_rejects_a_stalled_writer_with_residue() {
let _serial = tcp_write_probe::exclusive();
let (listener, _rcvbuf_shrunk) = make_backpressure_listener();
let addr = listener.local_addr().unwrap();
let (stream_tx, stream_rx) = std::sync::mpsc::channel();
let accept_thread = std::thread::spawn(move || {
if let Ok((stream, _)) = listener.accept() {
let _ = stream_tx.send(stream);
}
});
let stop_writing = Arc::new(AtomicBool::new(false));
let stop_flag = stop_writing.clone();
let writer_thread = std::thread::spawn(move || {
let peer = std::net::TcpStream::connect(addr).expect("writer connect");
peer.set_nonblocking(true).unwrap();
let chunk = [0u8; 8 * 1024];
while !stop_flag.load(Ordering::Acquire) {
match std::io::Write::write(&mut (&peer), &chunk) {
Ok(_) => {}
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
std::thread::sleep(Duration::from_millis(5));
}
Err(_) => break,
}
}
});
let stream = stream_rx
.recv_timeout(Duration::from_secs(10))
.expect("the synthetic writer never connected");
stream.set_nonblocking(true).unwrap();
let mut peek_buf = vec![0u8; 4 * 1024 * 1024];
let pinned = wait_for_receive_queue_plateau(
&stream,
&mut peek_buf,
Instant::now() + Duration::from_secs(20),
)
.expect("the synthetic writer must reach a first plateau");
prove_post_plateau_refill(
&stream,
&mut peek_buf,
pinned,
Instant::now() + Duration::from_secs(15),
)
.expect("the writer is alive through stage 2 — the stall comes next");
stop_writing.store(true, Ordering::Release);
writer_thread.join().expect("the synthetic writer panicked");
std::thread::sleep(Duration::from_millis(500));
require_flow_control_repin(
&stream,
&mut peek_buf,
Instant::now() + Duration::from_secs(20),
)
.expect("undrained residue pins again: stage 3 cannot see the stall");
let verdict = require_write_parked(Instant::now() + Duration::from_secs(4));
let rejection = verdict.expect_err(
"stage 4 accepted a scene with no tcp write in flight: the probe \
proves nothing and a stalled sibling would pass the wedge",
);
assert!(
rejection.contains("not parked inside a tcp write"),
"the rejection must name the missing in-flight write, got: {rejection}"
);
drop(stream);
let _ = accept_thread.join();
}
#[test]
fn blocked_sibling_stays_interruptible_while_sink_finalizes() {
let _serial = tcp_write_probe::exclusive();
let (listener, _rcvbuf_shrunk) = make_backpressure_listener();
let addr = listener.local_addr().unwrap();
let (stream_tx, stream_rx) = std::sync::mpsc::channel();
let accept_thread = std::thread::spawn(move || {
if let Ok((stream, _)) = listener.accept() {
pin_peer_rcvbuf(&stream);
let _ = stream_tx.send(stream);
}
});
let ends = Arc::new(AtomicUsize::new(0));
let errors = Arc::new(AtomicUsize::new(0));
let delivered_error = Arc::new(std::sync::Mutex::new(None::<String>));
let (ends_cb, errors_cb) = (ends.clone(), errors.clone());
let delivered_cb = delivered_error.clone();
let sink = PacketSink::builder(move |_pkt| Ok(()))
.on_end(move || {
ends_cb.fetch_add(1, Ordering::AcqRel);
})
.on_delivery_error(move |err| {
*delivered_cb
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(err.to_string());
errors_cb.fetch_add(1, Ordering::AcqRel);
})
.build();
let scheduler = FfmpegContext::builder()
.input(Input::from("testsrc2=s=1280x720:r=30").set_format("lavfi"))
.input(Input::from("sine=frequency=440").set_format("lavfi"))
.output(
Output::new_by_packet_sink(sink)
.set_audio_codec("aac")
.add_stream_map("1:a")
.set_recording_time_us(300_000),
)
.output(
Output::from(format!("tcp://{addr}?send_buffer_size=16384"))
.add_stream_map("0:v")
.set_format("mpegts")
.set_video_codec("mpeg4")
.set_video_codec_opt("qscale", "1"),
)
.build()
.unwrap()
.start()
.unwrap();
let stream = stream_rx
.recv_timeout(Duration::from_secs(20))
.expect("the sibling never connected to the TCP peer");
stream.set_nonblocking(true).unwrap();
let mut peek_buf = vec![0u8; 4 * 1024 * 1024];
let pinned = wait_for_receive_queue_plateau(
&stream,
&mut peek_buf,
Instant::now() + Duration::from_secs(30),
)
.expect("stage 1");
let _drained = prove_post_plateau_refill(
&stream,
&mut peek_buf,
pinned,
Instant::now() + Duration::from_secs(15),
)
.expect("stage 2");
let _repinned = require_flow_control_repin(
&stream,
&mut peek_buf,
Instant::now() + Duration::from_secs(20),
)
.expect("stage 3");
let stage4_deadline = Instant::now() + Duration::from_secs(60);
let (parked_gen, rcvbuf_at_park, unread_at_park) = loop {
let candidate = require_write_parked(stage4_deadline)
.expect("stage 4: the sibling must be parked inside a tcp write");
let (rcvbuf, unread) = peer_socket_stats(&stream);
if rcvbuf < 0 || unread >= rcvbuf {
break (candidate, rcvbuf, unread);
}
let horizon = Instant::now() + Duration::from_secs(8);
let frozen = loop {
std::thread::sleep(Duration::from_millis(500));
let returned = tcp_write_probe::RETURNED.load(Ordering::Acquire);
let entered = tcp_write_probe::ENTERED.load(Ordering::Acquire);
let (_, unread_now) = peer_socket_stats(&stream);
if (entered, returned) != (candidate, candidate - 1) || unread_now != unread {
break false;
}
if Instant::now() >= horizon {
break true;
}
};
if frozen {
break (candidate, rcvbuf, unread);
}
assert!(
Instant::now() < stage4_deadline,
"stage 4: every parked write kept absorbing window grants \
before the deadline (rcvbuf={rcvbuf} unread={unread})"
);
};
assert!(
!scheduler.is_ended(),
"the job settled during the wedge proof: the sibling exited instead \
of blocking, so stop() would be cutting nothing"
);
let sink_parked_deadline = Instant::now() + Duration::from_secs(10);
while scheduler.parked_settlement_waiters() == 0 {
assert!(
Instant::now() < sink_parked_deadline,
"the sink never parked in the settlement barrier: stop() would \
not be racing a finalizing sink"
);
std::thread::sleep(Duration::from_millis(2));
}
assert_eq!(
(ends.load(Ordering::Acquire), errors.load(Ordering::Acquire)),
(0, 0),
"a terminal sink event fired while the coordinator was still parked"
);
let (tx, rx) = std::sync::mpsc::channel();
let stop_worker = std::thread::spawn(move || {
let _ = tx.send(scheduler.stop());
});
let result = match rx.recv_timeout(Duration::from_secs(30)) {
Ok(result) => {
stop_worker.join().expect("the stop worker panicked");
result
}
Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
match stop_worker.join() {
Err(payload) => std::panic::resume_unwind(payload),
Ok(()) => panic!("the stop worker exited without reporting a result"),
}
}
Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
drop(stream);
let _ = stop_worker.join();
panic!("stop() hung: the sink held the finalize exemption over a blocked sibling");
}
};
let (rcvbuf_settled, unread_settled) = peer_socket_stats(&stream);
eprintln!(
"wedge peer at park: rcvbuf={rcvbuf_at_park} unread={unread_at_park}; \
settled: rcvbuf={rcvbuf_settled} unread={unread_settled}"
);
if receive_autotune_uncapped() {
eprintln!(
"wedge: skipping the cut acknowledgment: net.inet.tcp.autorcvbufmax \
exceeds the 16384 peer pin, the unread window regrows and the \
parked write can drain on its own (cap the sysctl to exercise \
the full property)"
);
return;
}
let entered = tcp_write_probe::ENTERED.load(Ordering::Acquire);
let returned = tcp_write_probe::RETURNED.load(Ordering::Acquire);
assert_eq!(
(entered, returned),
(parked_gen, parked_gen),
"tcp writes moved past the parked generation across stop()"
);
let last_ret = tcp_write_probe::LAST_RET.load(Ordering::Acquire);
assert!(
last_ret < 0,
"the parked write returned {last_ret} (success): stop() cut nothing \
(peer at park: rcvbuf={rcvbuf_at_park} unread={unread_at_park}; \
settled: rcvbuf={rcvbuf_settled} unread={unread_settled} — a grown \
unread count means the advertised window was not shut; a frozen one \
means the sender's own buffer absorbed the write)"
);
let err_gen = tcp_write_probe::LAST_ERR_GEN.load(Ordering::Acquire);
assert_eq!(
err_gen, parked_gen,
"the write that returned the error is not the parked one"
);
let cut_gen = tcp_write_probe::CUT_GEN.load(Ordering::Acquire);
assert_eq!(
cut_gen, parked_gen,
"no output-interrupt election happened inside the parked write: \
its failure was not stop()'s cut"
);
match &result {
Err(crate::error::Error::Muxing(
crate::error::MuxingOperationError::InterleavedWriteError(_),
)) => {}
other => panic!("stop() must surface the cut interleaved write, got {other:?}"),
}
let (end_count, error_count) = (ends.load(Ordering::Acquire), errors.load(Ordering::Acquire));
assert_eq!(
(end_count, error_count),
(0, 1),
"the finalizing sink must deliver exactly the cut's failure \
({end_count} end, {error_count} error)"
);
let delivered = delivered_error
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.take()
.expect("the delivery error must have been captured");
assert!(
delivered.contains("during interleaved write"),
"the sink must be handed the cut write's failure, got: {delivered}"
);
drop(stream);
let _ = accept_thread.join();
}