| decoder.rs |
|
15284 |
- |
| ffi.rs |
|
13126 |
- |
| lib.rs |
|
328 |
- |
| runner.rs |
Spreads one JXL decode's work across a thread pool dedicated to JXL decoding.
# Why a pool of our own
The helpers run on a different pool from the decode itself, which is what
makes waiting here safe: the thread that blocks and the threads it waits on
belong to different pools, so a blocked decode can never be holding a thread
that a helper needs. An AVIF decode does the same thing, fanning out to
dav1d's own threads.
The pool is a `SharedThreadPool`, so it costs nothing until the first
parallel decode in the process, it is shut down for us at
xpcom-shutdown-threads, and its threads are reaped once they go idle.
# Why the closure's lifetime is erased
The closure jxl-rs hands us borrows its decode state, so it is only valid for
the duration of the call. A helper is an `nsIRunnable`, which has to be
`'static`. Both cannot be true, so the lifetime is transmuted away and the
closure travels behind a raw pointer.
What puts the guarantee back is that the call does not return until every
helper it queued has been accounted for. `Helper` decrements the outstanding
count from its `Drop`, which runs whether the helper ran or was thrown away
without running, and `WaitForHelpers` blocks until that count is zero.
`WaitForHelpers` does its waiting from a destructor rather than from a
statement after the work, so it also covers the calling thread's own
invocation of the closure panicking, which would otherwise unwind past the
wait and leave helpers dereferencing a closure jxl-rs has taken back. Gecko
builds Rust with `panic=abort` so that unwind does not arise in Firefox, but
rusttests builds with unwinding.
Helpers are dispatched with `DISPATCH_FALLIBLE`, which asks the pool to
release a helper it cannot queue instead of leaking it, so a failed dispatch
runs the `Drop` as well.
# What this asks of the pool
This depends on a queued helper eventually either running or being released,
since the wait is for its payload's destructor. `nsThreadPool` has that
property: its threads drain the queue to empty before exiting, even once it
is shutting down, and `Shutdown` joins them. |
12421 |
- |