feat(mt): move flush error cleanup order into Rust
The MT flush state machine already recognized worker and checksum errors in Rust, but its single C error callback still bundled waiting for all workers with releasing job resources. That kept teardown order in C and made the two cleanup phases impossible to test independently. Split the C callback into private wait and release leaves, then pass both to Rust. Rust now owns the error cleanup sequence and always waits for workers before releasing their resources on either error path. The MT context, job resources, synchronization, and cleanup operations remain C-owned. Test Plan: - `rustup run nightly rustfmt --check --edition 2021 rust/src/zstdmt_compress.rs` -- passed under the 40 GiB virtual-memory cap. - `cc -fsyntax-only -std=c99` with the zstd include paths for `lib/compress/zstdmt_compress.c` -- passed under the cap. - `git diff --check` and `git diff --cached --check` -- passed. - Cargo, Make, native builds, fuzzers, and large tests were not run per the worker OOM and scope constraints.
This commit is contained in:
+39
-21
@@ -1017,7 +1017,8 @@ pub type ZSTDMT_flushUpdateJobFn =
|
||||
unsafe extern "C" fn(opaque: *mut c_void, job_id: c_uint, dst_flushed: usize);
|
||||
pub type ZSTDMT_flushCompleteJobFn =
|
||||
unsafe extern "C" fn(opaque: *mut c_void, job_id: c_uint, src_size: usize, c_size: usize);
|
||||
pub type ZSTDMT_flushErrorFn = unsafe extern "C" fn(opaque: *mut c_void);
|
||||
pub type ZSTDMT_flushWaitForAllJobsFn = unsafe extern "C" fn(opaque: *mut c_void);
|
||||
pub type ZSTDMT_flushReleaseAllJobResourcesFn = unsafe extern "C" fn(opaque: *mut c_void);
|
||||
|
||||
/// Scalar MT state used by the outer streaming scheduler. The C context,
|
||||
/// input-range ownership, and synchronization objects remain private to C;
|
||||
@@ -2337,7 +2338,7 @@ fn flush_produced_result(result: usize, output_pos: usize) -> ZSTDMT_flushProduc
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn flush_produced_with<P, C, U, F, E>(
|
||||
unsafe fn flush_produced_with<P, C, U, F, W, R>(
|
||||
context: ZSTDMT_flushContextProjection,
|
||||
output_dst: *mut c_void,
|
||||
output_size: usize,
|
||||
@@ -2348,14 +2349,16 @@ unsafe fn flush_produced_with<P, C, U, F, E>(
|
||||
mut add_frame_checksum: C,
|
||||
mut update_job: U,
|
||||
mut complete_job: F,
|
||||
mut on_error: E,
|
||||
mut wait_for_all_jobs: W,
|
||||
mut release_all_job_resources: R,
|
||||
) -> ZSTDMT_flushProducedResult
|
||||
where
|
||||
P: FnMut(c_uint, c_uint) -> ZSTDMT_flushJobProjection,
|
||||
C: FnMut(c_uint, &mut ZSTDMT_flushJobProjection),
|
||||
U: FnMut(c_uint, usize),
|
||||
F: FnMut(c_uint, usize, usize),
|
||||
E: FnMut(),
|
||||
W: FnMut(),
|
||||
R: FnMut(),
|
||||
{
|
||||
let mut output_pos = output_pos;
|
||||
let mut done_job_id = context.doneJobID;
|
||||
@@ -2367,7 +2370,8 @@ where
|
||||
let src_size = projection.srcSize;
|
||||
|
||||
if ERR_isError(projection.cSize) {
|
||||
on_error();
|
||||
wait_for_all_jobs();
|
||||
release_all_job_resources();
|
||||
return flush_produced_result(projection.cSize, output_pos);
|
||||
}
|
||||
|
||||
@@ -2379,7 +2383,8 @@ where
|
||||
}
|
||||
|
||||
if ERR_isError(projection.cSize) {
|
||||
on_error();
|
||||
wait_for_all_jobs();
|
||||
release_all_job_resources();
|
||||
return flush_produced_result(projection.cSize, output_pos);
|
||||
}
|
||||
|
||||
@@ -2612,7 +2617,8 @@ pub unsafe extern "C" fn ZSTDMT_rust_flushProduced(
|
||||
addFrameChecksum: Option<ZSTDMT_flushChecksumFn>,
|
||||
updateJob: Option<ZSTDMT_flushUpdateJobFn>,
|
||||
completeJob: Option<ZSTDMT_flushCompleteJobFn>,
|
||||
onError: Option<ZSTDMT_flushErrorFn>,
|
||||
waitForAllJobs: Option<ZSTDMT_flushWaitForAllJobsFn>,
|
||||
releaseAllJobResources: Option<ZSTDMT_flushReleaseAllJobResourcesFn>,
|
||||
) -> ZSTDMT_flushProducedResult {
|
||||
let Some(context) = (unsafe { context.as_ref() }).copied() else {
|
||||
return flush_produced_result(ERROR(ZstdErrorCode::Generic), output_pos);
|
||||
@@ -2622,13 +2628,15 @@ pub unsafe extern "C" fn ZSTDMT_rust_flushProduced(
|
||||
Some(add_frame_checksum),
|
||||
Some(update_job),
|
||||
Some(complete_job),
|
||||
Some(on_error),
|
||||
Some(wait_for_all_jobs),
|
||||
Some(release_all_job_resources),
|
||||
) = (
|
||||
projectJob,
|
||||
addFrameChecksum,
|
||||
updateJob,
|
||||
completeJob,
|
||||
onError,
|
||||
waitForAllJobs,
|
||||
releaseAllJobResources,
|
||||
)
|
||||
else {
|
||||
return flush_produced_result(ERROR(ZstdErrorCode::Generic), output_pos);
|
||||
@@ -2657,7 +2665,10 @@ pub unsafe extern "C" fn ZSTDMT_rust_flushProduced(
|
||||
complete_job(opaque, job_id, src_size, c_size);
|
||||
},
|
||||
|| {
|
||||
on_error(opaque);
|
||||
wait_for_all_jobs(opaque);
|
||||
},
|
||||
|| {
|
||||
release_all_job_resources(opaque);
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -6735,7 +6746,8 @@ mod tests {
|
||||
|_job_id, _projection| panic!("unexpected checksum callback"),
|
||||
|_job_id, dst_flushed| updated = Some(dst_flushed),
|
||||
|_job_id, src_size, c_size| completed = Some((src_size, c_size)),
|
||||
|| panic!("unexpected error callback"),
|
||||
|| panic!("unexpected wait callback"),
|
||||
|| panic!("unexpected release callback"),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -6784,7 +6796,8 @@ mod tests {
|
||||
|_job_id, _projection| panic!("unexpected checksum callback"),
|
||||
|_job_id, dst_flushed| updated = Some(dst_flushed),
|
||||
|_job_id, _src_size, _c_size| completed = true,
|
||||
|| panic!("unexpected error callback"),
|
||||
|| panic!("unexpected wait callback"),
|
||||
|| panic!("unexpected release callback"),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -6808,7 +6821,7 @@ mod tests {
|
||||
jobIDMask: 0,
|
||||
..ZSTDMT_flushContextProjection::default()
|
||||
};
|
||||
let mut error_cleanup = false;
|
||||
let mut error_cleanup = Vec::new();
|
||||
let result = unsafe {
|
||||
flush_produced_with(
|
||||
context,
|
||||
@@ -6821,12 +6834,13 @@ mod tests {
|
||||
|_job_id, _projection| panic!("unexpected checksum callback"),
|
||||
|_job_id, _dst_flushed| panic!("unexpected update callback"),
|
||||
|_job_id, _src_size, _c_size| panic!("unexpected completion callback"),
|
||||
|| error_cleanup = true,
|
||||
|| error_cleanup.push("wait"),
|
||||
|| error_cleanup.push("release"),
|
||||
)
|
||||
};
|
||||
assert_eq!(result.result, ERROR(ZstdErrorCode::Generic));
|
||||
assert_eq!(result.outputPos, 0);
|
||||
assert!(error_cleanup);
|
||||
assert_eq!(error_cleanup, ["wait", "release"]);
|
||||
|
||||
let job = [0x80u8, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86];
|
||||
let mut output = [0xa5u8; 8];
|
||||
@@ -6862,7 +6876,8 @@ mod tests {
|
||||
},
|
||||
|_job_id, _dst_flushed| {},
|
||||
|_job_id, _src_size, c_size| completed_size = Some(c_size),
|
||||
|| panic!("unexpected error callback"),
|
||||
|| panic!("unexpected wait callback"),
|
||||
|| panic!("unexpected release callback"),
|
||||
)
|
||||
};
|
||||
assert_eq!(checksum_calls, 1);
|
||||
@@ -6884,7 +6899,7 @@ mod tests {
|
||||
frameChecksumNeeded: 1,
|
||||
..ZSTDMT_flushJobProjection::default()
|
||||
};
|
||||
let mut error_cleanup = false;
|
||||
let mut error_cleanup = Vec::new();
|
||||
let mut completed = false;
|
||||
|
||||
let result = unsafe {
|
||||
@@ -6906,13 +6921,14 @@ mod tests {
|
||||
},
|
||||
|_job_id, _dst_flushed| panic!("unexpected update callback"),
|
||||
|_job_id, _src_size, _c_size| completed = true,
|
||||
|| error_cleanup = true,
|
||||
|| error_cleanup.push("wait"),
|
||||
|| error_cleanup.push("release"),
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(result.result, ERROR(ZstdErrorCode::DstSizeTooSmall));
|
||||
assert_eq!(result.outputPos, 0);
|
||||
assert!(error_cleanup);
|
||||
assert_eq!(error_cleanup, ["wait", "release"]);
|
||||
assert!(!completed);
|
||||
assert_eq!(output, [0xa5; 8]);
|
||||
}
|
||||
@@ -6990,7 +7006,8 @@ mod tests {
|
||||
|_job_id, _projection| panic!("no checksum expected"),
|
||||
|_job_id, _dst_flushed| panic!("no update expected"),
|
||||
|_job_id, _src_size, _c_size| panic!("no completion expected"),
|
||||
|| panic!("no error expected"),
|
||||
|| panic!("no wait expected"),
|
||||
|| panic!("no release expected"),
|
||||
)
|
||||
};
|
||||
assert_eq!(not_ended.result, 1);
|
||||
@@ -7012,7 +7029,8 @@ mod tests {
|
||||
|_job_id, _projection| panic!("no checksum expected"),
|
||||
|_job_id, _dst_flushed| panic!("no update expected"),
|
||||
|_job_id, _src_size, _c_size| panic!("no completion expected"),
|
||||
|| panic!("no error expected"),
|
||||
|| panic!("no wait expected"),
|
||||
|| panic!("no release expected"),
|
||||
)
|
||||
};
|
||||
assert_eq!(ended.result, 0);
|
||||
|
||||
Reference in New Issue
Block a user