From a5dfe8ab28f027e0b2a5860df26ec7ea6536ad0d Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Fri, 17 Oct 2025 17:27:33 +0200 Subject: [PATCH] handle multiple waiters for the same module --- src/browser/ScriptManager.zig | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index b166ca74..2dc43fe2 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -326,15 +326,28 @@ pub fn waitForModule(self: *ScriptManager, url: [:0]const u8) !GetResult { }; const sync = entry.value_ptr.*; + // We can have multiple scripts waiting for the same module in concurrency. + // We use the waiters to ensures only the last waiter deinit the resources. + sync.waiters += 1; + defer sync.waiters -= 1; + var client = self.client; while (true) { switch (sync.state) { .loading => {}, .done => { - // Our caller has its own higher level cache (caching the - // actual compiled module). There's no reason for us to keep this - defer self.sync_module_pool.destroy(sync); - defer self.sync_modules.removeByPtr(entry.key_ptr); + if (sync.waiters == 1) { + // Our caller has its own higher level cache (caching the + // actual compiled module). There's no reason for us to keep + // this if we are the last waiter. + defer self.sync_module_pool.destroy(sync); + defer self.sync_modules.removeByPtr(entry.key_ptr); + return .{ + .buffer = sync.buffer, + .buffer_pool = &self.buffer_pool, + }; + } + return .{ .buffer = sync.buffer, .buffer_pool = &self.buffer_pool, @@ -882,6 +895,8 @@ const SyncModule = struct { manager: *ScriptManager, buffer: std.ArrayListUnmanaged(u8) = .{}, state: State = .loading, + // number of waiters for the module. + waiters: u8 = 0, const State = union(enum) { done,