@@ -244,16 +244,14 @@ pub fn LocalRunQueue(comptime T: type, comptime stealable: bool) type {
244244 const t = self .ownTail ();
245245 const h = self .loadHead ();
246246 const space : usize = capacity - (t -% h );
247- var buf : [64 ]* T = undefined ;
248- const want = @min (space , @min (max , buf .len ));
247+ const max_batch = 64 ;
248+ const start : usize = t & mask ;
249+ const contiguous = capacity - start ;
250+ const want = @min (contiguous , @min (space , @min (max , max_batch )));
249251 if (want == 0 ) return ;
250- const got = self .overflow .popBatch (buf [0.. want ]);
251- var tt = t ;
252- for (buf [0.. got ]) | node | {
253- self .buffer [tt & mask ] = node ;
254- tt +%= 1 ;
255- }
256- if (got > 0 ) self .storeTail (tt );
252+
253+ const got = self .overflow .popBatch (self .buffer [start .. start + want ]);
254+ if (got > 0 ) self .storeTail (t +% @as (u32 , @intCast (got )));
257255 }
258256
259257 /// Number of tasks currently in the ring (used for maybeYield fairness).
@@ -414,6 +412,42 @@ test "LocalRunQueue: non-stealable variant pushes, pops, and overflows" {
414412 try testing .expect (q .isEmpty ());
415413}
416414
415+ test "LocalRunQueue: refill writes directly on both sides of ring wrap" {
416+ var ov : TestOverflow = .{};
417+ var q = TestLocalQueue .init (& ov );
418+ var nodes : [270 ]TestNode = undefined ;
419+
420+ // Advance both cursors near the physical end while leaving the ring empty.
421+ for (nodes [0.. 250], 0.. ) | * node , id | {
422+ node .* = .{ .id = id };
423+ _ = q .push (node );
424+ }
425+ for (0.. 250) | id | {
426+ try testing .expectEqual (id , (q .pop () orelse return error .Unexpected ).id );
427+ }
428+
429+ // The first refill stops at the physical end of the ring.
430+ for (nodes [250.. ], 250.. ) | * node , id | {
431+ node .* = .{ .id = id };
432+ ov .push (node );
433+ }
434+ q .refill (20 );
435+ try testing .expectEqual (6 , q .len ());
436+ try testing .expectEqual (14 , ov .len ());
437+ for (250.. 256) | id | {
438+ try testing .expectEqual (id , (q .pop () orelse return error .Unexpected ).id );
439+ }
440+
441+ // Once tail wraps, the next refill writes directly at the ring's start.
442+ q .refill (20 );
443+ try testing .expectEqual (14 , q .len ());
444+ try testing .expect (ov .isEmpty ());
445+ for (256.. 270) | id | {
446+ try testing .expectEqual (id , (q .pop () orelse return error .Unexpected ).id );
447+ }
448+ try testing .expect (q .isEmpty ());
449+ }
450+
417451test "LocalRunQueue: steal takes half into the thief and returns one" {
418452 var ov1 : TestOverflow = .{};
419453 var ov2 : TestOverflow = .{};
0 commit comments