diff --git a/src/main.zig b/src/main.zig index a4864c2..88c3871 100644 --- a/src/main.zig +++ b/src/main.zig @@ -429,6 +429,8 @@ fn readExcludeFile(path: [:0]const u8) !void { } pub fn main() void { + ui.main_thread = std.Thread.getCurrentId(); + // Grab thousands_sep from the current C locale. _ = c.setlocale(c.LC_ALL, ""); if (c.localeconv()) |locale| { @@ -574,6 +576,8 @@ var event_delay_timer: std.time.Timer = undefined; // Draw the screen and handle the next input event. // In non-blocking mode, screen drawing is rate-limited to keep this function fast. pub fn handleEvent(block: bool, force_draw: bool) void { + while (ui.oom_threads.load(.monotonic) > 0) ui.oom(); + if (block or force_draw or event_delay_timer.read() > config.update_delay) { if (ui.inited) _ = ui.c.erase(); switch (state) { diff --git a/src/ui.zig b/src/ui.zig index 8192443..a1bf12f 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -18,6 +18,8 @@ pub const c = @cImport({ }); pub var inited: bool = false; +pub var main_thread: std.Thread.Id = undefined; +pub var oom_threads = std.atomic.Value(usize).init(0); pub var rows: u32 = undefined; pub var cols: u32 = undefined; @@ -43,15 +45,21 @@ pub fn quit() noreturn { // Also, init() and other ncurses-related functions may have hidden allocation, // no clue if ncurses will consistently report OOM, but we're not handling that // right now. -// TODO: Make thread-safe! pub fn oom() void { - const haveui = inited; - deinit(); - const stderr = std.io.getStdErr(); - stderr.writeAll("\x1b7\x1b[JOut of memory, trying again in 1 second. Hit Ctrl-C to abort.\x1b8") catch {}; - std.time.sleep(std.time.ns_per_s); - if (haveui) - init(); + @setCold(true); + if (main_thread == std.Thread.getCurrentId()) { + const haveui = inited; + deinit(); + const stderr = std.io.getStdErr(); + stderr.writeAll("\x1b7\x1b[JOut of memory, trying again in 1 second. Hit Ctrl-C to abort.\x1b8") catch {}; + std.time.sleep(std.time.ns_per_s); + if (haveui) + init(); + } else { + _ = oom_threads.fetchAdd(1, .monotonic); + std.time.sleep(std.time.ns_per_s); + _ = oom_threads.fetchSub(1, .monotonic); + } } // Dumb strerror() alternative for Zig file I/O, not complete.