| ... | ... | @@ -124,13 +124,13 @@ pub const IO_Uring = struct { |
| 124 | 124 | self.fd = -1; |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | | /// Returns a vacant SQE, or an error if the submission queue is full. |
| 127 | /// Returns a pointer to a zeroed SQE, or an error if the submission queue is full. |
| 128 | 128 | /// We follow the implementation (and atomics) of liburing's `io_uring_get_sqe()` exactly. |
| 129 | 129 | /// However, instead of a null we return an error to force safe handling. |
| 130 | 130 | /// Any situation where the submission queue is full tends more towards a control flow error, |
| 131 | 131 | /// and the null return in liburing is more a C idiom than anything else, for lack of a better |
| 132 | 132 | /// alternative. In Zig, we have first-class error handling... so let's use it. |
| 133 | | /// Matches the implementation of io_uring_get_sqe() in liburing. |
| 133 | /// Matches the implementation of io_uring_get_sqe() in liburing, except zeroes for safety. |
| 134 | 134 | pub fn get_sqe(self: *IO_Uring) !*io_uring_sqe { |
| 135 | 135 | const head = @atomicLoad(u32, self.sq.head, .Acquire); |
| 136 | 136 | // Remember that these head and tail offsets wrap around every four billion operations. |
| ... | ... | @@ -139,6 +139,8 @@ pub const IO_Uring = struct { |
| 139 | 139 | if (next -% head > self.sq.sqes.len) return error.SubmissionQueueFull; |
| 140 | 140 | var sqe = &self.sq.sqes[self.sq.sqe_tail & self.sq.mask.*]; |
| 141 | 141 | self.sq.sqe_tail = next; |
| 142 | // We zero the SQE slot here in a single place, rather than in many `queue_` methods. |
| 143 | @memset(@ptrCast([*]u8, sqe), 0, @sizeOf(io_uring_sqe)); |
| 142 | 144 | return sqe; |
| 143 | 145 | } |
| 144 | 146 | |
| ... | ... | @@ -312,14 +314,12 @@ pub const IO_Uring = struct { |
| 312 | 314 | // sqe->addr2 holds a pointer to socklen_t, and finally sqe->accept_flags holds the flags |
| 313 | 315 | // for accept(4)." - https://lwn.net/ml/linux-block/20191025173037.13486-1-axboe@kernel.dk/ |
| 314 | 316 | const sqe = try self.get_sqe(); |
| 315 | | sqe.* = .{ |
| 316 | | .opcode = .ACCEPT, |
| 317 | | .fd = fd, |
| 318 | | .off = @ptrToInt(addrlen), // `addr2` is a newer union member that maps to `off`. |
| 319 | | .addr = @ptrToInt(addr), |
| 320 | | .user_data = user_data, |
| 321 | | .opflags = accept_flags |
| 322 | | }; |
| 317 | sqe.opcode = .ACCEPT; |
| 318 | sqe.fd = fd; |
| 319 | sqe.off = @ptrToInt(addrlen); // `addr2` is a newer union member that maps to `off`. |
| 320 | sqe.addr = @ptrToInt(addr); |
| 321 | sqe.user_data = user_data; |
| 322 | sqe.opflags = accept_flags; |
| 323 | 323 | return sqe; |
| 324 | 324 | } |
| 325 | 325 | |
| ... | ... | @@ -334,11 +334,9 @@ pub const IO_Uring = struct { |
| 334 | 334 | /// or else insert a full write barrier using `drain_previous_sqes()` when queueing an fsync. |
| 335 | 335 | pub fn queue_fsync(self: *IO_Uring, user_data: u64, fd: os.fd_t) !*io_uring_sqe { |
| 336 | 336 | const sqe = try self.get_sqe(); |
| 337 | | sqe.* = .{ |
| 338 | | .opcode = .FSYNC, |
| 339 | | .fd = fd, |
| 340 | | .user_data = user_data |
| 341 | | }; |
| 337 | sqe.opcode = .FSYNC; |
| 338 | sqe.fd = fd; |
| 339 | sqe.user_data = user_data; |
| 342 | 340 | return sqe; |
| 343 | 341 | } |
| 344 | 342 | |
| ... | ... | @@ -349,10 +347,8 @@ pub const IO_Uring = struct { |
| 349 | 347 | /// know when the ring is idle before acting on a kill signal. |
| 350 | 348 | pub fn queue_nop(self: *IO_Uring, user_data: u64) !*io_uring_sqe { |
| 351 | 349 | const sqe = try self.get_sqe(); |
| 352 | | sqe.* = .{ |
| 353 | | .opcode = .NOP, |
| 354 | | .user_data = user_data |
| 355 | | }; |
| 350 | sqe.opcode = .NOP; |
| 351 | sqe.user_data = user_data; |
| 356 | 352 | return sqe; |
| 357 | 353 | } |
| 358 | 354 | |
| ... | ... | @@ -366,14 +362,12 @@ pub const IO_Uring = struct { |
| 366 | 362 | offset: u64 |
| 367 | 363 | ) !*io_uring_sqe { |
| 368 | 364 | const sqe = try self.get_sqe(); |
| 369 | | sqe.* = .{ |
| 370 | | .opcode = .READ, |
| 371 | | .fd = fd, |
| 372 | | .off = offset, |
| 373 | | .addr = @ptrToInt(buffer.ptr), |
| 374 | | .len = @truncate(u32, buffer.len), |
| 375 | | .user_data = user_data |
| 376 | | }; |
| 365 | sqe.opcode = .READ; |
| 366 | sqe.fd = fd; |
| 367 | sqe.off = offset; |
| 368 | sqe.addr = @ptrToInt(buffer.ptr); |
| 369 | sqe.len = @truncate(u32, buffer.len); |
| 370 | sqe.user_data = user_data; |
| 377 | 371 | return sqe; |
| 378 | 372 | } |
| 379 | 373 | |
| ... | ... | @@ -387,14 +381,12 @@ pub const IO_Uring = struct { |
| 387 | 381 | offset: u64 |
| 388 | 382 | ) !*io_uring_sqe { |
| 389 | 383 | const sqe = try self.get_sqe(); |
| 390 | | sqe.* = .{ |
| 391 | | .opcode = .WRITE, |
| 392 | | .fd = fd, |
| 393 | | .off = offset, |
| 394 | | .addr = @ptrToInt(buffer.ptr), |
| 395 | | .len = @truncate(u32, buffer.len), |
| 396 | | .user_data = user_data |
| 397 | | }; |
| 384 | sqe.opcode = .WRITE; |
| 385 | sqe.fd = fd; |
| 386 | sqe.off = offset; |
| 387 | sqe.addr = @ptrToInt(buffer.ptr); |
| 388 | sqe.len = @truncate(u32, buffer.len); |
| 389 | sqe.user_data = user_data; |
| 398 | 390 | return sqe; |
| 399 | 391 | } |
| 400 | 392 | |
| ... | ... | @@ -410,14 +402,12 @@ pub const IO_Uring = struct { |
| 410 | 402 | offset: u64 |
| 411 | 403 | ) !*io_uring_sqe { |
| 412 | 404 | const sqe = try self.get_sqe(); |
| 413 | | sqe.* = .{ |
| 414 | | .opcode = .READV, |
| 415 | | .fd = fd, |
| 416 | | .off = offset, |
| 417 | | .addr = @ptrToInt(iovecs.ptr), |
| 418 | | .len = @truncate(u32, iovecs.len), |
| 419 | | .user_data = user_data |
| 420 | | }; |
| 405 | sqe.opcode = .READV; |
| 406 | sqe.fd = fd; |
| 407 | sqe.off = offset; |
| 408 | sqe.addr = @ptrToInt(iovecs.ptr); |
| 409 | sqe.len = @truncate(u32, iovecs.len); |
| 410 | sqe.user_data = user_data; |
| 421 | 411 | return sqe; |
| 422 | 412 | } |
| 423 | 413 | |
| ... | ... | @@ -433,14 +423,12 @@ pub const IO_Uring = struct { |
| 433 | 423 | offset: u64 |
| 434 | 424 | ) !*io_uring_sqe { |
| 435 | 425 | const sqe = try self.get_sqe(); |
| 436 | | sqe.* = .{ |
| 437 | | .opcode = .WRITEV, |
| 438 | | .fd = fd, |
| 439 | | .off = offset, |
| 440 | | .addr = @ptrToInt(iovecs.ptr), |
| 441 | | .len = @truncate(u32, iovecs.len), |
| 442 | | .user_data = user_data |
| 443 | | }; |
| 426 | sqe.opcode = .WRITEV; |
| 427 | sqe.fd = fd; |
| 428 | sqe.off = offset; |
| 429 | sqe.addr = @ptrToInt(iovecs.ptr); |
| 430 | sqe.len = @truncate(u32, iovecs.len); |
| 431 | sqe.user_data = user_data; |
| 444 | 432 | return sqe; |
| 445 | 433 | } |
| 446 | 434 | |