| ... | @@ -282,19 +282,15 @@ fn copy_cqes_ready(self: *IoUring, cqes: []linux.io_uring_cqe) u32 { | ... | @@ -282,19 +282,15 @@ fn copy_cqes_ready(self: *IoUring, cqes: []linux.io_uring_cqe) u32 { |
| 282 | const ready = self.cq_ready(); | 282 | const ready = self.cq_ready(); |
| 283 | const count = @min(cqes.len, ready); | 283 | const count = @min(cqes.len, ready); |
| 284 | const head = self.cq.head.* & self.cq.mask; | 284 | const head = self.cq.head.* & self.cq.mask; |
| 285 | const tail = (self.cq.head.* +% count) & self.cq.mask; | 285 | |
| 286 | | 286 | // before wrapping |
| 287 | if (head < tail) { | 287 | const n = @min(self.cq.cqes.len - head, count); |
| 288 | // head behind tail -> no wrapping | 288 | @memcpy(cqes[0..n], self.cq.cqes[head..][0..n]); |
| 289 | @memcpy(cqes[0..count], self.cq.cqes[head..tail]); | 289 | |
| 290 | } else { | 290 | if (count > n) { |
| 291 | // head in front of tail -> buffer wraps | 291 | // wrap self.cq.cqes |
| 292 | const two_copies_required: bool = self.cq.cqes.len - head < count; | 292 | const w = count - n; |
| 293 | const amount_to_copy_in_first = if (two_copies_required) self.cq.cqes.len - head else count; | 293 | @memcpy(cqes[n..][0..w], self.cq.cqes[0..w]); |
| 294 | @memcpy(cqes[0..amount_to_copy_in_first], self.cq.cqes[head .. head + amount_to_copy_in_first]); | | |
| 295 | if (two_copies_required) { | | |
| 296 | @memcpy(cqes[amount_to_copy_in_first..count], self.cq.cqes[0..tail]); | | |
| 297 | } | | |
| 298 | } | 294 | } |
| 299 | | 295 | |
| 300 | self.cq_advance(count); | 296 | self.cq_advance(count); |
| ... | @@ -4231,24 +4227,49 @@ fn expect_buf_grp_cqe( | ... | @@ -4231,24 +4227,49 @@ fn expect_buf_grp_cqe( |
| 4231 | return cqe; | 4227 | return cqe; |
| 4232 | } | 4228 | } |
| 4233 | | 4229 | |
| 4234 | test "failing test for issue 19451" { | 4230 | test "copy_cqes with wrapping sq.cqes buffer" { |
| 4235 | var ring = try IoUring.init(2, 0); | 4231 | if (!is_linux) return error.SkipZigTest; |
| | 4232 | |
| | 4233 | var ring = IoUring.init(2, 0) catch |err| switch (err) { |
| | 4234 | error.SystemOutdated => return error.SkipZigTest, |
| | 4235 | error.PermissionDenied => return error.SkipZigTest, |
| | 4236 | else => return err, |
| | 4237 | }; |
| 4236 | defer ring.deinit(); | 4238 | defer ring.deinit(); |
| 4237 | | 4239 | |
| 4238 | try testing.expectEqual(2, ring.sq.sqes.len); | 4240 | try testing.expectEqual(2, ring.sq.sqes.len); |
| 4239 | try testing.expectEqual(4, ring.cq.cqes.len); | 4241 | try testing.expectEqual(4, ring.cq.cqes.len); |
| 4240 | | 4242 | |
| 4241 | for (0..4) |i| { | 4243 | // submit 2 entries, receive 2 completions |
| 4242 | const sqe = try ring.get_sqe(); | 4244 | var cqes: [8]linux.io_uring_cqe = undefined; |
| 4243 | sqe.prep_timeout(&.{ .tv_sec = 0, .tv_nsec = 10000 }, 0, 0); | 4245 | { |
| 4244 | sqe.user_data = i; | 4246 | for (0..2) |_| { |
| 4245 | _ = try ring.submit(); | 4247 | const sqe = try ring.get_sqe(); |
| | 4248 | sqe.prep_timeout(&.{ .tv_sec = 0, .tv_nsec = 10000 }, 0, 0); |
| | 4249 | try testing.expect(try ring.submit() == 1); |
| | 4250 | } |
| | 4251 | var cqe_count: u32 = 0; |
| | 4252 | while (cqe_count < 2) { |
| | 4253 | cqe_count += try ring.copy_cqes(&cqes, 2 - cqe_count); |
| | 4254 | } |
| 4246 | } | 4255 | } |
| 4247 | | 4256 | |
| 4248 | var cqe_count: u32 = 0; | 4257 | try testing.expectEqual(2, ring.cq.head.*); |
| 4249 | while (cqe_count < 4) { | 4258 | |
| 4250 | var cqes: [8]linux.io_uring_cqe = undefined; | 4259 | // sq.sqes len is 4, starting at position 2 |
| 4251 | cqe_count += try ring.copy_cqes(&cqes, 4 - cqe_count); | 4260 | // every 4 entries submit wraps completion buffer |
| | 4261 | // we are reading ring.cq.cqes at indexes 2,3,0,1 |
| | 4262 | for (1..1024) |i| { |
| | 4263 | for (0..4) |_| { |
| | 4264 | const sqe = try ring.get_sqe(); |
| | 4265 | sqe.prep_timeout(&.{ .tv_sec = 0, .tv_nsec = 10000 }, 0, 0); |
| | 4266 | try testing.expect(try ring.submit() == 1); |
| | 4267 | } |
| | 4268 | var cqe_count: u32 = 0; |
| | 4269 | while (cqe_count < 4) { |
| | 4270 | cqe_count += try ring.copy_cqes(&cqes, 4 - cqe_count); |
| | 4271 | } |
| | 4272 | try testing.expectEqual(4, cqe_count); |
| | 4273 | try testing.expectEqual(2 + 4 * i, ring.cq.head.*); |
| 4252 | } | 4274 | } |
| 4253 | try testing.expectEqual(4, cqe_count); | | |
| 4254 | } | 4275 | } |