diff --git a/packages/bun-usockets/src/internal/internal.h b/packages/bun-usockets/src/internal/internal.h index f84e268621..0ac526e0d8 100644 --- a/packages/bun-usockets/src/internal/internal.h +++ b/packages/bun-usockets/src/internal/internal.h @@ -90,8 +90,8 @@ enum { #define POLL_TYPE_MASK (POLL_TYPE_KIND_MASK | POLL_TYPE_POLLING_MASK) /* Bun APIs implemented in Zig */ -void Bun__lock(uint32_t *lock); -void Bun__unlock(uint32_t *lock); +void Bun__lock(zig_mutex_t *lock); +void Bun__unlock(zig_mutex_t *lock); struct addrinfo_request; struct addrinfo_result_entry { diff --git a/packages/bun-usockets/src/internal/loop_data.h b/packages/bun-usockets/src/internal/loop_data.h index ddbaee9ffc..3a2186457d 100644 --- a/packages/bun-usockets/src/internal/loop_data.h +++ b/packages/bun-usockets/src/internal/loop_data.h @@ -20,6 +20,18 @@ #include +#if defined(__APPLE__) +#include +typedef os_unfair_lock zig_mutex_t; +#elif defined(__linux__) +typedef uint32_t zig_mutex_t; +#elif defined(_WIN32) +// SRWLOCK +typedef void* zig_mutex_t; +#else +#error "Unsupported platform" +#endif + // IMPORTANT: When changing this, don't forget to update the zig version in uws.zig as well! struct us_internal_loop_data_t { struct us_timer_t *sweep_timer; @@ -39,7 +51,7 @@ struct us_internal_loop_data_t { int low_prio_budget; struct us_connecting_socket_t *dns_ready_head; struct us_connecting_socket_t *closed_connecting_head; - uint32_t mutex; + zig_mutex_t mutex; void *parent_ptr; char parent_tag; /* We do not care if this flips or not, it doesn't matter */ diff --git a/packages/bun-usockets/src/loop.c b/packages/bun-usockets/src/loop.c index 0a26602d65..bbb1ff879d 100644 --- a/packages/bun-usockets/src/loop.c +++ b/packages/bun-usockets/src/loop.c @@ -21,38 +21,30 @@ #ifndef WIN32 #include #endif +#include "wtf/Platform.h" +#if ASSERT_ENABLED +extern const size_t Bun__lock__size; +extern void __attribute((__noreturn__)) Bun__panic(const char* message, size_t length); +#define BUN_PANIC(message) Bun__panic(message, sizeof(message) - 1) +#endif /* The loop has 2 fallthrough polls */ void us_internal_loop_data_init(struct us_loop_t *loop, void (*wakeup_cb)(struct us_loop_t *loop), void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop)) { + // We allocate with calloc, so we only need to initialize the specific fields in use. loop->data.sweep_timer = us_create_timer(loop, 1, 0); loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2); loop->data.send_buf = malloc(LIBUS_SEND_BUFFER_LENGTH); - loop->data.ssl_data = 0; - loop->data.head = 0; - loop->data.iterator = 0; - loop->data.closed_udp_head = 0; - loop->data.closed_head = 0; - loop->data.low_prio_head = 0; - loop->data.low_prio_budget = 0; - loop->data.pre_cb = pre_cb; loop->data.post_cb = post_cb; - loop->data.iteration_nr = 0; - - loop->data.closed_connecting_head = 0; - loop->data.dns_ready_head = 0; - loop->data.mutex = 0; - - loop->data.parent_ptr = 0; - loop->data.parent_tag = 0; - - loop->data.closed_context_head = 0; - loop->data.jsc_vm = 0; - loop->data.wakeup_async = us_internal_create_async(loop, 1, 0); us_internal_async_set(loop->data.wakeup_async, (void (*)(struct us_internal_async *)) wakeup_cb); +#if ASSERT_ENABLED + if (Bun__lock__size != sizeof(loop->data.mutex)) { + BUN_PANIC("The size of the mutex must match the size of the lock"); + } +#endif } void us_internal_loop_data_free(struct us_loop_t *loop) { diff --git a/src/Mutex.zig b/src/Mutex.zig index f344fd2f5e..7e824f2d82 100644 --- a/src/Mutex.zig +++ b/src/Mutex.zig @@ -57,7 +57,7 @@ const Impl = if (builtin.mode == .Debug and !builtin.single_threaded) else ReleaseImpl; -const ReleaseImpl = +pub const ReleaseImpl = if (builtin.os.tag == .windows) WindowsImpl else if (builtin.os.tag.isDarwin()) @@ -65,6 +65,8 @@ else if (builtin.os.tag.isDarwin()) else FutexImpl; +pub const ExternImpl = ReleaseImpl.Type; + const DebugImpl = struct { locking_thread: std.atomic.Value(Thread.Id) = std.atomic.Value(Thread.Id).init(0), // 0 means it's not locked. impl: ReleaseImpl = .{}, @@ -96,7 +98,7 @@ const DebugImpl = struct { // SRWLOCK on windows is almost always faster than Futex solution. // It also implements an efficient Condition with requeue support for us. const WindowsImpl = struct { - srwlock: windows.SRWLOCK = .{}, + srwlock: Type = .{}, fn tryLock(self: *@This()) bool { return windows.kernel32.TryAcquireSRWLockExclusive(&self.srwlock) != windows.FALSE; @@ -111,11 +113,13 @@ const WindowsImpl = struct { } const windows = std.os.windows; + + pub const Type = windows.SRWLOCK; }; // os_unfair_lock on darwin supports priority inheritance and is generally faster than Futex solutions. const DarwinImpl = struct { - oul: c.os_unfair_lock = .{}, + oul: Type = .{}, fn tryLock(self: *@This()) bool { return c.os_unfair_lock_trylock(&self.oul); @@ -130,6 +134,7 @@ const DarwinImpl = struct { } const c = std.c; + pub const Type = c.os_unfair_lock; }; const FutexImpl = struct { @@ -196,16 +201,22 @@ const FutexImpl = struct { Futex.wake(&self.state, 1); } } + + pub const Type = u32; }; const Mutex = @This(); pub fn spinCycle() void {} -export fn Bun__lock(ptr: *Mutex) void { +// These have to be a size known to C. +export fn Bun__lock(ptr: *ReleaseImpl) void { ptr.lock(); } -export fn Bun__unlock(ptr: *Mutex) void { +// These have to be a size known to C. +export fn Bun__unlock(ptr: *ReleaseImpl) void { ptr.unlock(); } + +export const Bun__lock__size: usize = @sizeOf(ReleaseImpl); diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 96d3be9657..3555261098 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -62,7 +62,7 @@ pub const InternalLoopData = extern struct { low_prio_budget: i32, dns_ready_head: *ConnectingSocket, closed_connecting_head: *ConnectingSocket, - mutex: u32, // this is actually a bun.Mutex + mutex: bun.Mutex.ReleaseImpl.Type, parent_ptr: ?*anyopaque, parent_tag: c_char, iteration_nr: usize,