Skip to content

jslok/worklets-deadlock

Repository files navigation

worklets-deadlock — minimal SuspendAll repro

Minimal reproduction of the WorkletRuntime::runSyncSerialized deadlock that fires on the com.margelo.camera.frame thread when a vision-camera frame processor calls a Nitro HybridObject method registered on the JS runtime.

What the bug looks like

After a few minutes of preview frames, the app SIGABRTs with:

F libc:  Fatal signal 6 (SIGABRT) in tid N (lo.camera.frame), pid M
F DEBUG: Abort message: 'Caused HeapTaskDaemon failure : SuspendAll timeout;
         remaining threads: Thread[..."com.margelo.camera.frame"]
         Final wait time: 10.012s; appr. total wait time: 24.028s'
F DEBUG: backtrace:
  #02 NonPI::MutexLockWithTimeout
  #03 std::__ndk1::recursive_mutex::lock()
  #04 libworklets.so
  #05 worklets::WorkletRuntime::runSyncSerialized
  ...
  #13 facebook::jsi::DecoratedHostFunction::operator()    ← inner HostFunction
  ...
  #20 facebook::jsi::DecoratedHostFunction::operator()    ← outer HostFunction
  ...
  #42 RuntimeDecorator::call                              ← worklet JS body
  #43 WithRuntimeDecorator<WorkletsReentrancyCheck>
  #45 WithRuntimeDecorator<worklets::AroundLock>          ← FP runtime lock held
  #46 margelo::nitro::SyncJSCallback::call                ← invoked by vision-camera

What's in the worklet

The frame processor runs exactly two HostFunction calls plus frame.dispose():

const gpu = resizer.resize(frame)  // HostFunction on JS-registered HybridObject
gpu.dispose()                       // HostFunction on JS-registered HybridObject
frame.dispose()                     // HostFunction on FP-registered HybridObject

frame.dispose() alone (in a loop, with no resizer) does not trigger the deadlock — Frame is created on the FP runtime, so the call is same-runtime and doesn't go through runSyncSerialized.

resize() and gpu.dispose() are called on a Resizer created by useResizer() in a React hook (JS runtime). Calling them from the FP runtime forces worklets to dispatch via DecoratedHostFunctionrunSyncSerialized → acquire the JS runtime's lock. After enough crossings the AB-BA pattern manifests:

  • A = worklets::AroundLock on the FP runtime, held by SyncJSCallback for the entire JS call (frame #45)
  • B = the JS runtime's recursive_mutex that runSyncSerialized needs (frame #03)

A is held by the camera frame thread waiting for B; B is held by the JS thread waiting for A. Neither releases. The Android ART HeapTaskDaemon then fails its SuspendAll and aborts the process.

Repro

npm install
npx expo prebuild --clean
npx expo run:android

Leave the app open on the camera preview. Within ~10 minutes (Pixel 10, Android 16, 30 fps) it will crash. In parallel:

adb logcat | grep -E "SuspendAll|signal 6|HardwareBuffer.close|Surface.release"

Versions

  • Expo SDK 55 (RN 0.83.4)
  • react-native-vision-camera ^5.0.10
  • react-native-vision-camera-resizer ^5.0.10
  • react-native-worklets ^0.8.3
  • react-native-nitro-modules ^0.35.7
  • react-native-nitro-image ^0.14.0
  • New Architecture enabled
  • Tested on: Pixel 10 / Android 16

What this rules in / out

  • Not a resizer-specific bug. Any Nitro HybridObject method registered on the JS runtime and called from the FP runtime takes the same DecoratedHostFunctionrunSyncSerialized path.
  • Not a workload-size bug. The minimal FP does no inference, no OpenCV, no JS allocations, no scheduleOnRN, and still deadlocks.
  • Not a HardwareBuffer leak. The HardwareBuffer.close failed warnings sometimes seen in the OP's repo do not always precede the deadlock — see the vision-camera tracker for separate Surface.release warnings.
  • Probabilistic, not deterministic. Time-to-crash scales with frame rate (~10 min at 30 fps, ~15 min at 60 fps with heavier per-frame work in the original repos).

License

MIT — share, fork, and link from issue trackers freely.

About

Minimal reproduction of the react-native-worklets SuspendAll deadlock on the vision-camera frame processor thread

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors