authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-15 11:00:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:49-07:00
log80069c1e69140ac240e5397270ea919ddbfce89b
tree2f62d43aa70b8911b05e8e5205b0594ba1355cbe
parentadaef433d24ce88230fe64ce20214d695cf83bc0

std.Io.Queue: add "uncancelable" variants to "get"

useful for resource management

1 files changed, 34 insertions(+), 8 deletions(-)

lib/std/Io.zig+34-8
...@@ -1315,10 +1315,23 @@ pub const TypeErasedQueue = struct {...@@ -1315,10 +1315,23 @@ pub const TypeErasedQueue = struct {
13151315
1316 pub fn get(q: *@This(), io: Io, buffer: []u8, min: usize) Cancelable!usize {1316 pub fn get(q: *@This(), io: Io, buffer: []u8, min: usize) Cancelable!usize {
1317 assert(buffer.len >= min);1317 assert(buffer.len >= min);
13181318 if (buffer.len == 0) return 0;
1319 try q.mutex.lock(io);1319 try q.mutex.lock(io);
1320 defer q.mutex.unlock(io);1320 defer q.mutex.unlock(io);
1321 return getLocked(q, io, buffer, min, false);
1322 }
1323
1324 pub fn getUncancelable(q: *@This(), io: Io, buffer: []u8, min: usize) usize {
1325 assert(buffer.len >= min);
1326 if (buffer.len == 0) return 0;
1327 q.mutex.lockUncancelable(io);
1328 defer q.mutex.unlock(io);
1329 return getLocked(q, io, buffer, min, true) catch |err| switch (err) {
1330 error.Canceled => unreachable,
1331 };
1332 }
13211333
1334 pub fn getLocked(q: *@This(), io: Io, buffer: []u8, min: usize, uncancelable: bool) Cancelable!usize {
1322 // The ring buffer gets first priority, then data should come from any1335 // The ring buffer gets first priority, then data should come from any
1323 // queued putters, then finally the ring buffer should be filled with1336 // queued putters, then finally the ring buffer should be filled with
1324 // data from putters so they can be resumed.1337 // data from putters so they can be resumed.
...@@ -1371,7 +1384,10 @@ pub const TypeErasedQueue = struct {...@@ -1371,7 +1384,10 @@ pub const TypeErasedQueue = struct {
13711384
1372 var pending: Get = .{ .remaining = remaining, .condition = .{}, .node = .{} };1385 var pending: Get = .{ .remaining = remaining, .condition = .{}, .node = .{} };
1373 q.getters.append(&pending.node);1386 q.getters.append(&pending.node);
1374 try pending.condition.wait(io, &q.mutex);1387 if (uncancelable)
1388 pending.condition.waitUncancelable(io, &q.mutex)
1389 else
1390 try pending.condition.wait(io, &q.mutex);
1375 remaining = pending.remaining;1391 remaining = pending.remaining;
1376 }1392 }
1377 }1393 }
...@@ -1439,6 +1455,14 @@ pub fn Queue(Elem: type) type {...@@ -1439,6 +1455,14 @@ pub fn Queue(Elem: type) type {
1439 return @divExact(q.type_erased.putUncancelable(io, @ptrCast(elements), min * @sizeOf(Elem)), @sizeOf(Elem));1455 return @divExact(q.type_erased.putUncancelable(io, @ptrCast(elements), min * @sizeOf(Elem)), @sizeOf(Elem));
1440 }1456 }
14411457
1458 pub fn putOne(q: *@This(), io: Io, item: Elem) Cancelable!void {
1459 assert(try q.put(io, &.{item}, 1) == 1);
1460 }
1461
1462 pub fn putOneUncancelable(q: *@This(), io: Io, item: Elem) void {
1463 assert(q.putUncancelable(io, &.{item}, 1) == 1);
1464 }
1465
1442 /// Receives elements from the beginning of the queue. The function1466 /// Receives elements from the beginning of the queue. The function
1443 /// returns when at least `min` elements have been populated inside1467 /// returns when at least `min` elements have been populated inside
1444 /// `buffer`.1468 /// `buffer`.
...@@ -1450,12 +1474,8 @@ pub fn Queue(Elem: type) type {...@@ -1450,12 +1474,8 @@ pub fn Queue(Elem: type) type {
1450 return @divExact(try q.type_erased.get(io, @ptrCast(buffer), min * @sizeOf(Elem)), @sizeOf(Elem));1474 return @divExact(try q.type_erased.get(io, @ptrCast(buffer), min * @sizeOf(Elem)), @sizeOf(Elem));
1451 }1475 }
14521476
1453 pub fn putOne(q: *@This(), io: Io, item: Elem) Cancelable!void {1477 pub fn getUncancelable(q: *@This(), io: Io, buffer: []Elem, min: usize) usize {
1454 assert(try q.put(io, &.{item}, 1) == 1);1478 return @divExact(q.type_erased.getUncancelable(io, @ptrCast(buffer), min * @sizeOf(Elem)), @sizeOf(Elem));
1455 }
1456
1457 pub fn putOneUncancelable(q: *@This(), io: Io, item: Elem) void {
1458 assert(q.putUncancelable(io, &.{item}, 1) == 1);
1459 }1479 }
14601480
1461 pub fn getOne(q: *@This(), io: Io) Cancelable!Elem {1481 pub fn getOne(q: *@This(), io: Io) Cancelable!Elem {
...@@ -1464,6 +1484,12 @@ pub fn Queue(Elem: type) type {...@@ -1464,6 +1484,12 @@ pub fn Queue(Elem: type) type {
1464 return buf[0];1484 return buf[0];
1465 }1485 }
14661486
1487 pub fn getOneUncancelable(q: *@This(), io: Io) Elem {
1488 var buf: [1]Elem = undefined;
1489 assert(q.getUncancelable(io, &buf, 1) == 1);
1490 return buf[0];
1491 }
1492
1467 /// Returns buffer length in `Elem` units.1493 /// Returns buffer length in `Elem` units.
1468 pub fn capacity(q: *const @This()) usize {1494 pub fn capacity(q: *const @This()) usize {
1469 return @divExact(q.type_erased.buffer.len, @sizeOf(Elem));1495 return @divExact(q.type_erased.buffer.len, @sizeOf(Elem));