| ... | @@ -108,7 +108,7 @@ pub const IO_Uring = struct { | ... | @@ -108,7 +108,7 @@ pub const IO_Uring = struct { |
| 108 | // Check that our starting state is as we expect. | 108 | // Check that our starting state is as we expect. |
| 109 | assert(sq.head.* == 0); | 109 | assert(sq.head.* == 0); |
| 110 | assert(sq.tail.* == 0); | 110 | assert(sq.tail.* == 0); |
| 111 | assert(sq.mask.* == p.sq_entries - 1); | 111 | assert(sq.mask == p.sq_entries - 1); |
| 112 | // Allow flags.* to be non-zero, since the kernel may set IORING_SQ_NEED_WAKEUP at any time. | 112 | // Allow flags.* to be non-zero, since the kernel may set IORING_SQ_NEED_WAKEUP at any time. |
| 113 | assert(sq.dropped.* == 0); | 113 | assert(sq.dropped.* == 0); |
| 114 | assert(sq.array.len == p.sq_entries); | 114 | assert(sq.array.len == p.sq_entries); |
| ... | @@ -118,7 +118,7 @@ pub const IO_Uring = struct { | ... | @@ -118,7 +118,7 @@ pub const IO_Uring = struct { |
| 118 | | 118 | |
| 119 | assert(cq.head.* == 0); | 119 | assert(cq.head.* == 0); |
| 120 | assert(cq.tail.* == 0); | 120 | assert(cq.tail.* == 0); |
| 121 | assert(cq.mask.* == p.cq_entries - 1); | 121 | assert(cq.mask == p.cq_entries - 1); |
| 122 | assert(cq.overflow.* == 0); | 122 | assert(cq.overflow.* == 0); |
| 123 | assert(cq.cqes.len == p.cq_entries); | 123 | assert(cq.cqes.len == p.cq_entries); |
| 124 | | 124 | |
| ... | @@ -152,7 +152,7 @@ pub const IO_Uring = struct { | ... | @@ -152,7 +152,7 @@ pub const IO_Uring = struct { |
| 152 | // We must therefore use wrapping addition and subtraction to avoid a runtime crash. | 152 | // We must therefore use wrapping addition and subtraction to avoid a runtime crash. |
| 153 | const next = self.sq.sqe_tail +% 1; | 153 | const next = self.sq.sqe_tail +% 1; |
| 154 | if (next -% head > self.sq.sqes.len) return error.SubmissionQueueFull; | 154 | if (next -% head > self.sq.sqes.len) return error.SubmissionQueueFull; |
| 155 | var sqe = &self.sq.sqes[self.sq.sqe_tail & self.sq.mask.*]; | 155 | var sqe = &self.sq.sqes[self.sq.sqe_tail & self.sq.mask]; |
| 156 | self.sq.sqe_tail = next; | 156 | self.sq.sqe_tail = next; |
| 157 | // We zero the SQE slot here in a single place, rather than in many `queue_` methods. | 157 | // We zero the SQE slot here in a single place, rather than in many `queue_` methods. |
| 158 | @memset(@ptrCast([*]u8, sqe), 0, @sizeOf(io_uring_sqe)); | 158 | @memset(@ptrCast([*]u8, sqe), 0, @sizeOf(io_uring_sqe)); |
| ... | @@ -224,11 +224,10 @@ pub const IO_Uring = struct { | ... | @@ -224,11 +224,10 @@ pub const IO_Uring = struct { |
| 224 | if (self.sq.sqe_head != self.sq.sqe_tail) { | 224 | if (self.sq.sqe_head != self.sq.sqe_tail) { |
| 225 | // Fill in SQEs that we have queued up, adding them to the kernel ring. | 225 | // Fill in SQEs that we have queued up, adding them to the kernel ring. |
| 226 | const to_submit = self.sq.sqe_tail -% self.sq.sqe_head; | 226 | const to_submit = self.sq.sqe_tail -% self.sq.sqe_head; |
| 227 | const mask = self.sq.mask.*; | | |
| 228 | var tail = self.sq.tail.*; | 227 | var tail = self.sq.tail.*; |
| 229 | var i: usize = 0; | 228 | var i: usize = 0; |
| 230 | while (i < to_submit) : (i += 1) { | 229 | while (i < to_submit) : (i += 1) { |
| 231 | self.sq.array[tail & mask] = self.sq.sqe_head & mask; | 230 | self.sq.array[tail & self.sq.mask] = self.sq.sqe_head & self.sq.mask; |
| 232 | tail +%= 1; | 231 | tail +%= 1; |
| 233 | self.sq.sqe_head +%= 1; | 232 | self.sq.sqe_head +%= 1; |
| 234 | } | 233 | } |
| ... | @@ -292,14 +291,13 @@ pub const IO_Uring = struct { | ... | @@ -292,14 +291,13 @@ pub const IO_Uring = struct { |
| 292 | fn copy_cqes_ready(self: *IO_Uring, cqes: []io_uring_cqe, wait_nr: u32) u32 { | 291 | fn copy_cqes_ready(self: *IO_Uring, cqes: []io_uring_cqe, wait_nr: u32) u32 { |
| 293 | const ready = self.cq_ready(); | 292 | const ready = self.cq_ready(); |
| 294 | const count = std.math.min(cqes.len, ready); | 293 | const count = std.math.min(cqes.len, ready); |
| 295 | const mask = self.cq.mask.*; | | |
| 296 | var head = self.cq.head.*; | 294 | var head = self.cq.head.*; |
| 297 | var tail = head +% count; | 295 | var tail = head +% count; |
| 298 | // TODO Optimize this by using 1 or 2 memcpy's (if the tail wraps) rather than a loop. | 296 | // TODO Optimize this by using 1 or 2 memcpy's (if the tail wraps) rather than a loop. |
| 299 | var i: usize = 0; | 297 | var i: usize = 0; |
| 300 | // Do not use "less-than" operator since head and tail may wrap: | 298 | // Do not use "less-than" operator since head and tail may wrap: |
| 301 | while (head != tail) { | 299 | while (head != tail) { |
| 302 | cqes[i] = self.cq.cqes[head & mask]; // Copy struct by value. | 300 | cqes[i] = self.cq.cqes[head & self.cq.mask]; // Copy struct by value. |
| 303 | head +%= 1; | 301 | head +%= 1; |
| 304 | i += 1; | 302 | i += 1; |
| 305 | } | 303 | } |
| ... | @@ -560,7 +558,7 @@ pub const IO_Uring = struct { | ... | @@ -560,7 +558,7 @@ pub const IO_Uring = struct { |
| 560 | pub const SubmissionQueue = struct { | 558 | pub const SubmissionQueue = struct { |
| 561 | head: *u32, | 559 | head: *u32, |
| 562 | tail: *u32, | 560 | tail: *u32, |
| 563 | mask: *u32, | 561 | mask: u32, |
| 564 | flags: *u32, | 562 | flags: *u32, |
| 565 | dropped: *u32, | 563 | dropped: *u32, |
| 566 | array: []u32, | 564 | array: []u32, |
| ... | @@ -618,7 +616,7 @@ pub const SubmissionQueue = struct { | ... | @@ -618,7 +616,7 @@ pub const SubmissionQueue = struct { |
| 618 | return SubmissionQueue { | 616 | return SubmissionQueue { |
| 619 | .head = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.head])), | 617 | .head = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.head])), |
| 620 | .tail = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.tail])), | 618 | .tail = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.tail])), |
| 621 | .mask = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.ring_mask])), | 619 | .mask = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.ring_mask])).*, |
| 622 | .flags = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.flags])), | 620 | .flags = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.flags])), |
| 623 | .dropped = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.dropped])), | 621 | .dropped = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.sq_off.dropped])), |
| 624 | .array = array[0..p.sq_entries], | 622 | .array = array[0..p.sq_entries], |
| ... | @@ -637,7 +635,7 @@ pub const SubmissionQueue = struct { | ... | @@ -637,7 +635,7 @@ pub const SubmissionQueue = struct { |
| 637 | pub const CompletionQueue = struct { | 635 | pub const CompletionQueue = struct { |
| 638 | head: *u32, | 636 | head: *u32, |
| 639 | tail: *u32, | 637 | tail: *u32, |
| 640 | mask: *u32, | 638 | mask: u32, |
| 641 | overflow: *u32, | 639 | overflow: *u32, |
| 642 | cqes: []io_uring_cqe, | 640 | cqes: []io_uring_cqe, |
| 643 | | 641 | |
| ... | @@ -656,7 +654,7 @@ pub const CompletionQueue = struct { | ... | @@ -656,7 +654,7 @@ pub const CompletionQueue = struct { |
| 656 | return CompletionQueue { | 654 | return CompletionQueue { |
| 657 | .head = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.head])), | 655 | .head = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.head])), |
| 658 | .tail = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.tail])), | 656 | .tail = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.tail])), |
| 659 | .mask = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.ring_mask])), | 657 | .mask = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.ring_mask])).*, |
| 660 | .overflow = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.overflow])), | 658 | .overflow = @ptrCast(*u32, @alignCast(@alignOf(u32), &mmap[p.cq_off.overflow])), |
| 661 | .cqes = cqes[0..p.cq_entries] | 659 | .cqes = cqes[0..p.cq_entries] |
| 662 | }; | 660 | }; |
| ... | @@ -670,7 +668,7 @@ pub const CompletionQueue = struct { | ... | @@ -670,7 +668,7 @@ pub const CompletionQueue = struct { |
| 670 | | 668 | |
| 671 | test "structs and offsets" { | 669 | test "structs and offsets" { |
| 672 | if (builtin.os.tag != .linux) return error.SkipZigTest; | 670 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| 673 | | 671 | |
| 674 | testing.expectEqual(@as(usize, 120), @sizeOf(io_uring_params)); | 672 | testing.expectEqual(@as(usize, 120), @sizeOf(io_uring_params)); |
| 675 | testing.expectEqual(@as(usize, 64), @sizeOf(io_uring_sqe)); | 673 | testing.expectEqual(@as(usize, 64), @sizeOf(io_uring_sqe)); |
| 676 | testing.expectEqual(@as(usize, 16), @sizeOf(io_uring_cqe)); | 674 | testing.expectEqual(@as(usize, 16), @sizeOf(io_uring_cqe)); |