authorgravatar for joran@ronomon.comJoran Dirk Greef <joran@ronomon.com> 2020-09-19 18:17:06+02:00
committergravatar for joran@ronomon.comJoran Dirk Greef <joran@ronomon.com> 2020-09-19 18:17:06+02:00
logba18420b277a8de21a760387767dcf2c9227cc5a
tree4112beb727856040101247c70c2b000083539b21
parente7ae6f2fadcafc7a4f0eea96815b7d22049dd2c5

Zero the SQE slot and assign, instead of initializing with default values


1 files changed, 39 insertions(+), 51 deletions(-)

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