Skip to content

Commit fbe087b

Browse files
committed
Fix nbio failure on windows
1 parent f894818 commit fbe087b

File tree

1 file changed

+9
-32
lines changed

1 file changed

+9
-32
lines changed

nbio_mbox/nbio_mbox.odin

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -43,46 +43,28 @@ Nbio_Mailbox_Error :: enum {
4343
// _NBio_State holds the nbio event loop and keepalive timer for one nbio_mbox instance.
4444
@(private)
4545
_NBio_State :: struct {
46-
loop: ^nbio.Event_Loop,
47-
keepalive: ^nbio.Operation,
48-
allocator: mem.Allocator,
49-
ref_count: int, // atomic
50-
wake_pending: bool, // atomic — guards the cross-thread timeout queue (capacity 128)
46+
loop: ^nbio.Event_Loop,
47+
keepalive: ^nbio.Operation,
48+
allocator: mem.Allocator,
5149
}
5250

5351
// _noop is the required no-op callback for nbio operations (used by keepalive timer).
5452
@(private)
5553
_noop :: proc(_: ^nbio.Operation) {}
5654

57-
// _noop_clear clears the wake_pending flag and releases a reference.
58-
// Runs in the event-loop thread after timeout fires.
59-
@(private)
60-
_noop_clear :: proc(_: ^nbio.Operation, state: ^_NBio_State) {
61-
intrinsics.atomic_store(&state.wake_pending, false)
62-
if intrinsics.atomic_add(&state.ref_count, -1) == 1 {
63-
free(state, state.allocator)
64-
}
65-
}
66-
67-
// _nbio_wake fires a zero-duration timeout to wake the nbio event loop.
68-
// Uses an atomic CAS flag so at most one timeout is queued at a time, preventing
69-
// the 128-slot cross-thread queue from overflowing under high-frequency sends.
55+
// _nbio_wake wakes the nbio event loop via nbio.wake_up.
56+
// Uses QueueUserAPC on Windows — no cross-thread operation allocation, no 128-slot queue.
57+
// Safe to call from any thread.
7058
@(private)
7159
_nbio_wake :: proc(ctx: rawptr) {
7260
if ctx == nil {
7361
return
7462
}
7563
state := (^_NBio_State)(ctx)
76-
// CAS false→true. Returns old value; if old != false, wake already pending — skip.
77-
if intrinsics.atomic_compare_exchange_strong(&state.wake_pending, false, true) != false {
78-
return
79-
}
80-
// Take a reference for the pending timeout task.
81-
intrinsics.atomic_add(&state.ref_count, 1)
82-
nbio.timeout_poly(0, state, _noop_clear, state.loop)
64+
nbio.wake_up(state.loop)
8365
}
8466

85-
// _nbio_close removes the keepalive timer and releases the primary reference.
67+
// _nbio_close removes the keepalive timer and frees state.
8668
// Must be called from the event-loop thread — nbio.remove panics cross-thread.
8769
@(private)
8870
_nbio_close :: proc(ctx: rawptr) {
@@ -94,11 +76,7 @@ _nbio_close :: proc(ctx: rawptr) {
9476
nbio.remove(state.keepalive)
9577
state.keepalive = nil
9678
}
97-
if intrinsics.atomic_add(&state.ref_count, -1) == 1 {
98-
free(state, state.allocator) // no pending callback — free now
99-
} else {
100-
nbio.tick(0) // drain pending _noop_clear → it will free state
101-
}
79+
free(state, state.allocator)
10280
}
10381

10482
@(private)
@@ -115,7 +93,6 @@ _init_timeout_wakeup :: proc(
11593
}
11694
state.loop = loop
11795
state.allocator = allocator
118-
state.ref_count = 1
11996
state.keepalive = nbio.timeout(time.Hour * 24, _noop, loop)
12097
if state.keepalive == nil {
12198
free(state, allocator)

0 commit comments

Comments
 (0)