refactor(compress): move heap CCtx initialization to Rust
Move the ordering-sensitive setup of a privately allocated compression context behind a Rust callback coordinator while keeping allocation and context storage in C. The explicit callback ABI preserves zeroing, custom allocator publication, BMI2 setup, and parameter-reset order, including reset-error propagation. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml --all-targets (775 passed) - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets (179 passed) - ulimit -v 41943040; make -j1 - ulimit -v 41943040; make -j1 -C tests test (all tests completed successfully)
This commit is contained in:
@@ -2120,6 +2120,61 @@ pub unsafe extern "C" fn ZSTD_rust_refThreadPool(
|
||||
0
|
||||
}
|
||||
|
||||
type InitCCtxCallbackFn = unsafe extern "C" fn(*mut c_void);
|
||||
type InitCCtxSetCustomMemFn = unsafe extern "C" fn(*mut c_void, *const c_void);
|
||||
type InitCCtxResetFn = unsafe extern "C" fn(*mut c_void) -> usize;
|
||||
|
||||
/// Explicit projection for private heap-CCtx initialization.
|
||||
///
|
||||
/// Rust owns the initialization ordering while C retains the private context
|
||||
/// layout, allocator publication, CPU-feature query, and reset operation
|
||||
/// behind callbacks.
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_rust_initCCtxState {
|
||||
callback_context: *mut c_void,
|
||||
custom_mem: *const c_void,
|
||||
zero: InitCCtxCallbackFn,
|
||||
set_custom_mem: InitCCtxSetCustomMemFn,
|
||||
set_bmi2: InitCCtxCallbackFn,
|
||||
reset: InitCCtxResetFn,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
assert!(size_of::<InitCCtxCallbackFn>() == size_of::<usize>());
|
||||
assert!(size_of::<InitCCtxSetCustomMemFn>() == size_of::<usize>());
|
||||
assert!(size_of::<InitCCtxResetFn>() == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_initCCtxState, callback_context) == 0);
|
||||
assert!(offset_of!(ZSTD_rust_initCCtxState, custom_mem) == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_initCCtxState, zero) == 2 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_initCCtxState, set_custom_mem) == 3 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_initCCtxState, set_bmi2) == 4 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_initCCtxState, reset) == 5 * size_of::<usize>());
|
||||
assert!(size_of::<ZSTD_rust_initCCtxState>() == 6 * size_of::<usize>());
|
||||
};
|
||||
|
||||
/// Initialize a heap-owned C compression context in the original order.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_initCCtx(state: *const ZSTD_rust_initCCtxState) -> usize {
|
||||
if state.is_null() {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
let state = unsafe { &*state };
|
||||
if state.callback_context.is_null() || state.custom_mem.is_null() {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(state.zero)(state.callback_context);
|
||||
(state.set_custom_mem)(state.callback_context, state.custom_mem);
|
||||
(state.set_bmi2)(state.callback_context);
|
||||
let result = (state.reset)(state.callback_context);
|
||||
if ERR_isError(result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
type CreateCCtxValidateCustomMemFn = unsafe extern "C" fn(*mut c_void) -> c_int;
|
||||
type CreateCCtxAllocateFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
|
||||
type CreateCCtxInitFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
||||
@@ -17745,6 +17800,85 @@ mod tests {
|
||||
assert!(context.initialized.is_null());
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct InitCCtxTestContext {
|
||||
events: Vec<&'static str>,
|
||||
reset_result: usize,
|
||||
}
|
||||
|
||||
unsafe fn init_cctx_test_context(context: *mut c_void) -> &'static mut InitCCtxTestContext {
|
||||
unsafe { &mut *context.cast::<InitCCtxTestContext>() }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn init_cctx_test_zero(context: *mut c_void) {
|
||||
unsafe { init_cctx_test_context(context) }
|
||||
.events
|
||||
.push("zero");
|
||||
}
|
||||
|
||||
unsafe extern "C" fn init_cctx_test_set_custom_mem(
|
||||
context: *mut c_void,
|
||||
_custom_mem: *const c_void,
|
||||
) {
|
||||
unsafe { init_cctx_test_context(context) }
|
||||
.events
|
||||
.push("set-custom-mem");
|
||||
}
|
||||
|
||||
unsafe extern "C" fn init_cctx_test_set_bmi2(context: *mut c_void) {
|
||||
unsafe { init_cctx_test_context(context) }
|
||||
.events
|
||||
.push("set-bmi2");
|
||||
}
|
||||
|
||||
unsafe extern "C" fn init_cctx_test_reset(context: *mut c_void) -> usize {
|
||||
let context = unsafe { init_cctx_test_context(context) };
|
||||
context.events.push("reset");
|
||||
context.reset_result
|
||||
}
|
||||
|
||||
fn init_cctx_test_state(context: &mut InitCCtxTestContext) -> ZSTD_rust_initCCtxState {
|
||||
ZSTD_rust_initCCtxState {
|
||||
callback_context: (context as *mut InitCCtxTestContext).cast(),
|
||||
custom_mem: ptr::dangling(),
|
||||
zero: init_cctx_test_zero,
|
||||
set_custom_mem: init_cctx_test_set_custom_mem,
|
||||
set_bmi2: init_cctx_test_set_bmi2,
|
||||
reset: init_cctx_test_reset,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_cctx_runs_private_initialization_steps_in_order() {
|
||||
let mut context = InitCCtxTestContext::default();
|
||||
let state = init_cctx_test_state(&mut context);
|
||||
|
||||
let result = unsafe { ZSTD_rust_initCCtx(&state) };
|
||||
|
||||
assert_eq!(result, 0);
|
||||
assert_eq!(
|
||||
context.events,
|
||||
["zero", "set-custom-mem", "set-bmi2", "reset"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_cctx_propagates_reset_errors_after_initialization_steps() {
|
||||
let mut context = InitCCtxTestContext {
|
||||
reset_result: ERROR(ZstdErrorCode::MemoryAllocation),
|
||||
..Default::default()
|
||||
};
|
||||
let state = init_cctx_test_state(&mut context);
|
||||
|
||||
let result = unsafe { ZSTD_rust_initCCtx(&state) };
|
||||
|
||||
assert_eq!(result, ERROR(ZstdErrorCode::MemoryAllocation));
|
||||
assert_eq!(
|
||||
context.events,
|
||||
["zero", "set-custom-mem", "set-bmi2", "reset"]
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct InitStaticCCtxTestContext {
|
||||
events: Vec<&'static str>,
|
||||
|
||||
Reference in New Issue
Block a user