By way of an update, I reworked the code that used these inputs to poll all the ADCs from a single thread on a deterministic schedule, on the presumption that the underlying problem was some kind of low-level timing malarkey to do with two reads being too close together.
That has either fixed it or made the interval between lockups much longer.
I'd still be interested to know how NativeAdc.fetchSamples() can hang up, but it's not an immediate problem.
R.