@@ -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