Skip to content

Commit ce1bffb

Browse files
Merge pull request #300 from karlseguin/macos_pseudo_cancel
"Implement" timeout cancellation for MacOS
2 parents 66f9305 + 9116b14 commit ce1bffb

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

src/loop.zig

+37-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ pub const SingleThreaded = struct {
4949
// This is a weak way to cancel all future Zig callbacks.
5050
zig_ctx_id: u32 = 0,
5151

52+
// The MacOS event loop doesn't support cancellation. We use this to track
53+
// cancellation ids and, on the timeout callback, we can can check here
54+
// to see if it's been cancelled.
55+
cancelled: std.AutoHashMapUnmanaged(usize, void),
56+
5257
cancel_pool: MemoryPool(ContextCancel),
5358
timeout_pool: MemoryPool(ContextTimeout),
5459
event_callback_pool: MemoryPool(EventCallbackContext),
@@ -63,6 +68,7 @@ pub const SingleThreaded = struct {
6368
pub fn init(alloc: std.mem.Allocator) !Self {
6469
return Self{
6570
.alloc = alloc,
71+
.cancelled = .{},
6672
.io = try IO.init(32, 0),
6773
.js_events_nb = 0,
6874
.zig_events_nb = 0,
@@ -81,11 +87,14 @@ pub const SingleThreaded = struct {
8187
break;
8288
};
8389
}
84-
self.cancelAll();
90+
if (comptime CANCEL_SUPPORTED) {
91+
self.cancelAll();
92+
}
8593
self.io.deinit();
8694
self.cancel_pool.deinit();
8795
self.timeout_pool.deinit();
8896
self.event_callback_pool.deinit();
97+
self.cancelled.deinit(self.alloc);
8998
}
9099

91100
// Retrieve all registred I/O events completed by OS kernel,
@@ -156,6 +165,12 @@ pub const SingleThreaded = struct {
156165
loop.alloc.destroy(completion);
157166
}
158167

168+
if (comptime CANCEL_SUPPORTED == false) {
169+
if (loop.cancelled.remove(@intFromPtr(completion))) {
170+
return;
171+
}
172+
}
173+
159174
// If the loop's context id has changed, don't call the js callback
160175
// function. The callback's memory has already be cleaned and the
161176
// events nb reset.
@@ -240,10 +255,22 @@ pub const SingleThreaded = struct {
240255
}
241256

242257
pub fn cancel(self: *Self, id: usize, js_cbk: ?JSCallback) !void {
258+
const alloc = self.alloc;
259+
if (comptime CANCEL_SUPPORTED == false) {
260+
try self.cancelled.put(alloc, id, {});
261+
if (js_cbk) |cbk| {
262+
var vcbk = cbk;
263+
defer vcbk.deinit(alloc);
264+
vcbk.call(null) catch {
265+
self.cbk_error = true;
266+
};
267+
}
268+
return;
269+
}
243270
const comp_cancel: *IO.Completion = @ptrFromInt(id);
244271

245-
const completion = try self.alloc.create(Completion);
246-
errdefer self.alloc.destroy(completion);
272+
const completion = try alloc.create(Completion);
273+
errdefer alloc.destroy(completion);
247274
completion.* = undefined;
248275

249276
const ctx = self.alloc.create(ContextCancel) catch unreachable;
@@ -267,6 +294,7 @@ pub const SingleThreaded = struct {
267294
pub fn resetJS(self: *Self) void {
268295
self.js_ctx_id += 1;
269296
self.resetEvents(.js);
297+
self.cancelled.clearRetainingCapacity();
270298
}
271299

272300
// Reset all existing Zig callbacks.
@@ -431,3 +459,9 @@ const EventCallbackContext = struct {
431459
ctx: *anyopaque,
432460
loop: *SingleThreaded,
433461
};
462+
463+
const CANCEL_SUPPORTED = switch (builtin.target.os.tag) {
464+
.linux => true,
465+
.macos, .tvos, .watchos, .ios => false,
466+
else => @compileError("IO is not supported for platform"),
467+
};

0 commit comments

Comments
 (0)