@@ -41,6 +41,9 @@ pub const Loop = struct {
4141 // event are finished.
4242 events_nb : usize ,
4343
44+ // Used to stop repeating timeouts when loop.run is called.
45+ stopping : bool ,
46+
4447 // ctx_id is incremented each time the loop is reset.
4548 // All callbacks store an initial ctx_id and compare before execution.
4649 // If a ctx is outdated, the callback is ignored.
@@ -62,11 +65,12 @@ pub const Loop = struct {
6265 pub const ConnectError = IO .ConnectError ;
6366
6467 pub fn init (alloc : std.mem.Allocator ) ! Self {
65- return Self {
68+ return . {
6669 .alloc = alloc ,
6770 .cancelled = .{},
6871 .io = try IO .init (32 , 0 ),
6972 .events_nb = 0 ,
73+ .stopping = false ,
7074 .timeout_pool = MemoryPool (ContextTimeout ).init (alloc ),
7175 .event_callback_pool = MemoryPool (EventCallbackContext ).init (alloc ),
7276 };
@@ -98,6 +102,10 @@ pub const Loop = struct {
98102 // Note that I/O events callbacks might register more I/O events
99103 // on the go when they are executed (ie. nested I/O events).
100104 pub fn run (self : * Self ) ! void {
105+ // stop repeating / interval timeouts from re-registering
106+ self .stopping = true ;
107+ defer self .stopping = false ;
108+
101109 while (self .eventsNb () > 0 ) {
102110 try self .io .run_for_ns (10 * std .time .ns_per_ms );
103111 // at each iteration we might have new events registred by previous callbacks
@@ -134,6 +142,7 @@ pub const Loop = struct {
134142 const ContextTimeout = struct {
135143 loop : * Self ,
136144 ctx_id : u32 ,
145+ initial : bool = true ,
137146 callback_node : ? * CallbackNode ,
138147 };
139148
@@ -145,8 +154,11 @@ pub const Loop = struct {
145154 var repeating = false ;
146155 const loop = ctx .loop ;
147156
148- defer {
157+ if ( ctx . initial ) {
149158 loop .removeEvent ();
159+ }
160+
161+ defer {
150162 if (repeating == false ) {
151163 loop .timeout_pool .destroy (ctx );
152164 loop .alloc .destroy (completion );
@@ -174,10 +186,13 @@ pub const Loop = struct {
174186 if (ctx .callback_node ) | cn | {
175187 var repeat_in : ? u63 = null ;
176188 cn .func (cn , & repeat_in );
177- if (repeat_in ) | r | {
178- // prevents our context and completion from being cleaned up
179- repeating = true ;
180- loop .scheduleTimeout (r , ctx , completion );
189+ if (loop .stopping == false ) {
190+ if (repeat_in ) | r | {
191+ // prevents our context and completion from being cleaned up
192+ repeating = true ;
193+ ctx .initial = false ;
194+ loop .scheduleTimeout (r , ctx , completion );
195+ }
181196 }
182197 }
183198 }
@@ -195,12 +210,12 @@ pub const Loop = struct {
195210 .callback_node = callback_node ,
196211 };
197212
213+ self .addEvent ();
198214 self .scheduleTimeout (nanoseconds , ctx , completion );
199215 return @intFromPtr (completion );
200216 }
201217
202218 fn scheduleTimeout (self : * Self , nanoseconds : u63 , ctx : * ContextTimeout , completion : * Completion ) void {
203- self .addEvent ();
204219 self .io .timeout (* ContextTimeout , ctx , timeoutCallback , completion , nanoseconds );
205220 }
206221
0 commit comments