feat(oakrender): render-process isolation S1 - dispatcher, scheduler, real worker
Per the M15 design (docs/zh/plans/riir/M15-render-process-isolation.md): - ipc.rs moved into oakrender with protocol v2: hello_caps, render_batch, batch_accepted, frame_failed; main-process-assigned slots; BGRA8 slot format. POSIX shm verified to 1GiB on macOS. - ProcessDispatcher: spawns oak-worker processes, handshake, stdio NDJSON control, shm segment lifecycle with generation-tagged keys, crash detection with bounded restart and frame redispatch, zero-copy ShmFrameRef delivery and copy counters. - PreviewScheduler: interleaved batch claiming (frame % W per worker, no work stealing), seek > playback-distance > background priority, credit-based flow control, crash recovery. - oak-worker renders for real: graph snapshot deserialization, montage decode+composite straight into the assigned shm slot, F32->BGRA8 final conversion in-worker, OFX plugin executor installed in-worker, crash hooks for isolation testing. Thread pool coexists for now (S2 removes it). Integration tests cover two-worker zero-copy rendering, crash isolation with redelivery, and real H.264 footage decode into slots.
This commit is contained in:
@@ -16,13 +16,15 @@
|
||||
|
||||
//! The worker layer (C++ RenderWorkerPool + RenderThread +
|
||||
//! workerprocess/workerjson): thread pool AND process-isolated pool
|
||||
//! behind one enum.
|
||||
//! behind one dispatch seam.
|
||||
//!
|
||||
//! This pass ships the in-process [`WorkerPool`] fully. The
|
||||
//! [`ProcessPool`] (crash isolation via oakengine_ipc worker processes)
|
||||
//! is a documented stub: the oakengine_ipc C ABI worker binary is not
|
||||
//! wired into the Rust world yet, so `start`/`post` fail with
|
||||
//! `Error::Failed` and the crash-isolation tests are `#[ignore]`d.
|
||||
//! process-isolated backend landed in M15 S1 as
|
||||
//! [`crate::procpool::ProcessDispatcher`] (spawn/handshake/crash-restart
|
||||
//! of oak-worker binaries over NDJSON + shared memory); both backends
|
||||
//! implement the [`JobDispatch`] seam the ticket arena posts through.
|
||||
//! [`ProcessPool`] below is the frozen pre-M15 facade stub kept for C
|
||||
//! ABI parity.
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
@@ -52,6 +54,21 @@ fn lock<T>(m: &Mutex<T>) -> MutexGuard<'_, T> {
|
||||
m.lock().unwrap_or_else(|e| e.into_inner())
|
||||
}
|
||||
|
||||
/// The job-dispatch seam (M15 S1): the ticket arena posts [`Job`]s
|
||||
/// through this interface without knowing the backend. Implemented by
|
||||
/// the in-process [`WorkerPool`] (threads) and the process-isolated
|
||||
/// [`crate::procpool::ProcessDispatcher`] (oak-worker children); S2
|
||||
/// removes the thread pool and this seam becomes process-only.
|
||||
pub trait JobDispatch: Send + Sync {
|
||||
/// Enqueue a job; false when the backend is gone (the arena then
|
||||
/// delivers the completion itself with `Error::State`).
|
||||
fn post(&self, job: Job) -> bool;
|
||||
|
||||
/// Stop accepting work, deliver the queued completions (cancelled)
|
||||
/// and release the backend. Idempotent.
|
||||
fn shutdown(&self);
|
||||
}
|
||||
|
||||
/// Thread-pool backend (C++ RenderThread model). Cheap to clone (all
|
||||
/// state is behind an `Arc`); the manager and the ticket arena share one
|
||||
/// pool.
|
||||
@@ -132,6 +149,12 @@ impl WorkerPool {
|
||||
/// without running); running jobs are joined so no completion fires
|
||||
/// after shutdown returns.
|
||||
pub fn shutdown(&mut self) {
|
||||
self.shutdown_ref();
|
||||
}
|
||||
|
||||
/// [`Self::shutdown`] on a shared reference (the [`JobDispatch`]
|
||||
/// seam; all state is interior-mutable). Idempotent.
|
||||
pub fn shutdown_ref(&self) {
|
||||
// Set the flag and wake the workers while holding the queue lock.
|
||||
// Workers decide whether to block in `cv.wait` while holding that
|
||||
// lock, so a flag set outside it could land between a worker's
|
||||
@@ -158,6 +181,16 @@ impl WorkerPool {
|
||||
}
|
||||
}
|
||||
|
||||
impl JobDispatch for WorkerPool {
|
||||
fn post(&self, job: Job) -> bool {
|
||||
WorkerPool::post(self, job)
|
||||
}
|
||||
|
||||
fn shutdown(&self) {
|
||||
self.shutdown_ref();
|
||||
}
|
||||
}
|
||||
|
||||
fn worker_loop(inner: Arc<PoolInner>) {
|
||||
loop {
|
||||
let job = {
|
||||
|
||||
Reference in New Issue
Block a user