feat(mt): move serial wait loop into Rust
Move the serial turn wait loop out of zstdmt_compress.c and into a Rust entry point. Rust now owns the lock, condition-wait, and ready/skip ordering policy while C retains pthread synchronization behind lock and wait callbacks. The projection documents that the mutex remains locked on return for the serial advance callback, preserving the existing worker synchronization contract. Add ABI layout checks and focused tests for both waiting and skip paths. Test Plan: - cargo fmt --manifest-path rust/Cargo.toml -- --check - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml zstdmt_compress::tests::serial_wait_for_turn -- --nocapture - ulimit -v 41943040 && make -j1
This commit is contained in:
@@ -361,6 +361,24 @@ typedef void (*ZSTDMT_serialGenerateLdmFn)(
|
||||
typedef void (*ZSTDMT_serialUpdateChecksumFn)(
|
||||
void* opaque, const void* src, size_t srcSize);
|
||||
typedef void (*ZSTDMT_serialAdvanceFn)(void* opaque);
|
||||
typedef void (*ZSTDMT_serialStateLockFn)(void* opaque);
|
||||
typedef void (*ZSTDMT_serialStateWaitFn)(void* opaque);
|
||||
typedef struct {
|
||||
void* callbackContext;
|
||||
unsigned* nextJobID;
|
||||
ZSTDMT_serialStateLockFn lock;
|
||||
ZSTDMT_serialStateWaitFn wait;
|
||||
unsigned jobID;
|
||||
} ZSTDMT_RustSerialWaitForTurnState;
|
||||
typedef char ZSTDMT_rust_serial_wait_for_turn_state_layout[
|
||||
(offsetof(ZSTDMT_RustSerialWaitForTurnState, callbackContext) == 0
|
||||
&& offsetof(ZSTDMT_RustSerialWaitForTurnState, nextJobID) == sizeof(void*)
|
||||
&& offsetof(ZSTDMT_RustSerialWaitForTurnState, lock) == 2 * sizeof(void*)
|
||||
&& offsetof(ZSTDMT_RustSerialWaitForTurnState, wait) == 3 * sizeof(void*)
|
||||
&& offsetof(ZSTDMT_RustSerialWaitForTurnState, jobID) == 4 * sizeof(void*)
|
||||
&& sizeof(ZSTDMT_RustSerialWaitForTurnState) == 5 * sizeof(void*)) ? 1 : -1];
|
||||
int ZSTDMT_rust_serialStateWaitForTurn(
|
||||
const ZSTDMT_RustSerialWaitForTurnState* state);
|
||||
void ZSTDMT_rust_serialStateGenSequences(
|
||||
ZSTDMT_RustRawSeqStore* seqStore, const void* src, size_t srcSize,
|
||||
unsigned jobID, int ldmEnabled, int checksumEnabled, void* opaque,
|
||||
@@ -1089,18 +1107,32 @@ static void ZSTDMT_serialState_free(SerialState* serialState)
|
||||
ZSTDMT_serialState_freeTables);
|
||||
}
|
||||
|
||||
static void ZSTDMT_serialState_lock(void* opaque)
|
||||
{
|
||||
SerialState* const serialState = (SerialState*)opaque;
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
|
||||
}
|
||||
|
||||
static void ZSTDMT_serialState_wait(void* opaque)
|
||||
{
|
||||
SerialState* const serialState = (SerialState*)opaque;
|
||||
DEBUGLOG(5, "wait for serialState->cond");
|
||||
ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex);
|
||||
}
|
||||
|
||||
/* Rust owns the serial turn/skip decision and operation ordering. The wait
|
||||
* callback intentionally leaves the main serial mutex locked; the advance
|
||||
* callback releases it after Rust has performed the current turn's work. */
|
||||
static int ZSTDMT_serialState_waitForTurn(void* opaque, unsigned jobID)
|
||||
{
|
||||
SerialState* const serialState = (SerialState*)opaque;
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
|
||||
while (serialState->nextJobID < jobID) {
|
||||
DEBUGLOG(5, "wait for serialState->cond");
|
||||
ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex);
|
||||
}
|
||||
return serialState->nextJobID == jobID;
|
||||
ZSTDMT_RustSerialWaitForTurnState state;
|
||||
state.callbackContext = serialState;
|
||||
state.nextJobID = &serialState->nextJobID;
|
||||
state.lock = ZSTDMT_serialState_lock;
|
||||
state.wait = ZSTDMT_serialState_wait;
|
||||
state.jobID = jobID;
|
||||
return ZSTDMT_rust_serialStateWaitForTurn(&state);
|
||||
}
|
||||
|
||||
static void ZSTDMT_serialState_generateLdm(
|
||||
|
||||
Reference in New Issue
Block a user