Tags: romgrk/node-gtk
Tags
fix: stop GApplication busy-spin at 100% CPU under ESM (#477) Under ES modules the blocking main-loop entry (Gio.Application.run, GLib.MainLoop.run, Gtk.main) is deferred to a macrotask so pending Promise/async continuations keep draining (#442). That deferral used setImmediate, whose callback runs inside Node's immediate-processing machinery (native CheckImmediate -> processImmediate). Because run() never returns -- it blocks in the GLib main loop until the app quits -- CheckImmediate never reaches the code that stops Node's private immediate uv_idle handle, so that handle stays active forever. An active idle handle pins uv_backend_timeout() at 0, which makes the nested uv-in-GLib loop busy-spin at 100% CPU and starves the application (worst on Node 26 / libuv 1.52, where the immediate's wakeup eventfd also stays signalled). Defer with setTimeout(..., 0) instead: a one-shot timer is removed from libuv's timer heap before its callback runs, so blocking inside it leaves no libuv state active and the loop can sleep normally. Still a macrotask, so the #442 microtask-draining fix is preserved. Adds a regression test (tests/loop__esm_idle_cpu) that runs an idle GApplication under ESM and asserts it does not busy-spin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PreviousNext