| ... | @@ -1272,7 +1272,7 @@ pub const TypeErasedQueue = struct { | ... | @@ -1272,7 +1272,7 @@ pub const TypeErasedQueue = struct { |
| 1272 | if (elements.len == 0) return 0; | 1272 | if (elements.len == 0) return 0; |
| 1273 | try q.mutex.lock(io); | 1273 | try q.mutex.lock(io); |
| 1274 | defer q.mutex.unlock(io); | 1274 | defer q.mutex.unlock(io); |
| 1275 | return putLocked(q, io, elements, min, false); | 1275 | return q.putLocked(io, elements, min, false); |
| 1276 | } | 1276 | } |
| 1277 | | 1277 | |
| 1278 | /// Same as `put` but cannot be canceled. | 1278 | /// Same as `put` but cannot be canceled. |
| ... | @@ -1281,7 +1281,7 @@ pub const TypeErasedQueue = struct { | ... | @@ -1281,7 +1281,7 @@ pub const TypeErasedQueue = struct { |
| 1281 | if (elements.len == 0) return 0; | 1281 | if (elements.len == 0) return 0; |
| 1282 | q.mutex.lockUncancelable(io); | 1282 | q.mutex.lockUncancelable(io); |
| 1283 | defer q.mutex.unlock(io); | 1283 | defer q.mutex.unlock(io); |
| 1284 | return putLocked(q, io, elements, min, true) catch |err| switch (err) { | 1284 | return q.putLocked(io, elements, min, true) catch |err| switch (err) { |
| 1285 | error.Canceled => unreachable, | 1285 | error.Canceled => unreachable, |
| 1286 | }; | 1286 | }; |
| 1287 | } | 1287 | } |
| ... | @@ -1291,50 +1291,49 @@ pub const TypeErasedQueue = struct { | ... | @@ -1291,50 +1291,49 @@ pub const TypeErasedQueue = struct { |
| 1291 | // queue is empty do we start populating the buffer. | 1291 | // queue is empty do we start populating the buffer. |
| 1292 | | 1292 | |
| 1293 | var remaining = elements; | 1293 | var remaining = elements; |
| 1294 | while (true) { | 1294 | while (q.getters.popFirst()) |getter_node| { |
| 1295 | const getter: *Get = @alignCast(@fieldParentPtr("node", q.getters.popFirst() orelse break)); | 1295 | const getter: *Get = @alignCast(@fieldParentPtr("node", getter_node)); |
| 1296 | const copy_len = @min(getter.remaining.len, remaining.len); | 1296 | const copy_len = @min(getter.remaining.len, remaining.len); |
| | 1297 | assert(copy_len > 0); |
| 1297 | @memcpy(getter.remaining[0..copy_len], remaining[0..copy_len]); | 1298 | @memcpy(getter.remaining[0..copy_len], remaining[0..copy_len]); |
| 1298 | remaining = remaining[copy_len..]; | 1299 | remaining = remaining[copy_len..]; |
| 1299 | getter.remaining = getter.remaining[copy_len..]; | 1300 | getter.remaining = getter.remaining[copy_len..]; |
| 1300 | if (getter.remaining.len == 0) { | 1301 | if (getter.remaining.len == 0) { |
| 1301 | getter.condition.signal(io); | 1302 | getter.condition.signal(io); |
| 1302 | continue; | 1303 | if (remaining.len > 0) continue; |
| 1303 | } | 1304 | } else q.getters.prepend(getter_node); |
| 1304 | q.getters.prepend(&getter.node); | | |
| 1305 | assert(remaining.len == 0); | 1305 | assert(remaining.len == 0); |
| 1306 | return elements.len; | 1306 | return elements.len; |
| 1307 | } | 1307 | } |
| 1308 | | 1308 | |
| 1309 | while (true) { | 1309 | { |
| 1310 | { | 1310 | const available = q.buffer[q.put_index..]; |
| 1311 | const available = q.buffer[q.put_index..]; | 1311 | const copy_len = @min(available.len, remaining.len); |
| 1312 | const copy_len = @min(available.len, remaining.len); | 1312 | @memcpy(available[0..copy_len], remaining[0..copy_len]); |
| 1313 | @memcpy(available[0..copy_len], remaining[0..copy_len]); | 1313 | remaining = remaining[copy_len..]; |
| 1314 | remaining = remaining[copy_len..]; | 1314 | q.put_index += copy_len; |
| 1315 | q.put_index += copy_len; | 1315 | if (remaining.len == 0) return elements.len; |
| 1316 | if (remaining.len == 0) return elements.len; | 1316 | } |
| 1317 | } | 1317 | { |
| 1318 | { | 1318 | const available = q.buffer[0..q.get_index]; |
| 1319 | const available = q.buffer[0..q.get_index]; | 1319 | const copy_len = @min(available.len, remaining.len); |
| 1320 | const copy_len = @min(available.len, remaining.len); | 1320 | @memcpy(available[0..copy_len], remaining[0..copy_len]); |
| 1321 | @memcpy(available[0..copy_len], remaining[0..copy_len]); | 1321 | remaining = remaining[copy_len..]; |
| 1322 | remaining = remaining[copy_len..]; | 1322 | q.put_index = copy_len; |
| 1323 | q.put_index = copy_len; | 1323 | if (remaining.len == 0) return elements.len; |
| 1324 | if (remaining.len == 0) return elements.len; | | |
| 1325 | } | | |
| 1326 | | | |
| 1327 | const total_filled = elements.len - remaining.len; | | |
| 1328 | if (total_filled >= min) return total_filled; | | |
| 1329 | | | |
| 1330 | var pending: Put = .{ .remaining = remaining, .condition = .{}, .node = .{} }; | | |
| 1331 | q.putters.append(&pending.node); | | |
| 1332 | if (uncancelable) | | |
| 1333 | pending.condition.waitUncancelable(io, &q.mutex) | | |
| 1334 | else | | |
| 1335 | try pending.condition.wait(io, &q.mutex); | | |
| 1336 | remaining = pending.remaining; | | |
| 1337 | } | 1324 | } |
| | 1325 | |
| | 1326 | const total_filled = elements.len - remaining.len; |
| | 1327 | if (total_filled >= min) return total_filled; |
| | 1328 | |
| | 1329 | var pending: Put = .{ .remaining = remaining, .condition = .{}, .node = .{} }; |
| | 1330 | q.putters.append(&pending.node); |
| | 1331 | defer if (pending.remaining.len > 0) q.putters.remove(&pending.node); |
| | 1332 | while (pending.remaining.len > 0) if (uncancelable) |
| | 1333 | pending.condition.waitUncancelable(io, &q.mutex) |
| | 1334 | else |
| | 1335 | try pending.condition.wait(io, &q.mutex); |
| | 1336 | return elements.len; |
| 1338 | } | 1337 | } |
| 1339 | | 1338 | |
| 1340 | pub fn get(q: *@This(), io: Io, buffer: []u8, min: usize) Cancelable!usize { | 1339 | pub fn get(q: *@This(), io: Io, buffer: []u8, min: usize) Cancelable!usize { |
| ... | @@ -1342,7 +1341,7 @@ pub const TypeErasedQueue = struct { | ... | @@ -1342,7 +1341,7 @@ pub const TypeErasedQueue = struct { |
| 1342 | if (buffer.len == 0) return 0; | 1341 | if (buffer.len == 0) return 0; |
| 1343 | try q.mutex.lock(io); | 1342 | try q.mutex.lock(io); |
| 1344 | defer q.mutex.unlock(io); | 1343 | defer q.mutex.unlock(io); |
| 1345 | return getLocked(q, io, buffer, min, false); | 1344 | return q.getLocked(io, buffer, min, false); |
| 1346 | } | 1345 | } |
| 1347 | | 1346 | |
| 1348 | pub fn getUncancelable(q: *@This(), io: Io, buffer: []u8, min: usize) usize { | 1347 | pub fn getUncancelable(q: *@This(), io: Io, buffer: []u8, min: usize) usize { |
| ... | @@ -1350,99 +1349,113 @@ pub const TypeErasedQueue = struct { | ... | @@ -1350,99 +1349,113 @@ pub const TypeErasedQueue = struct { |
| 1350 | if (buffer.len == 0) return 0; | 1349 | if (buffer.len == 0) return 0; |
| 1351 | q.mutex.lockUncancelable(io); | 1350 | q.mutex.lockUncancelable(io); |
| 1352 | defer q.mutex.unlock(io); | 1351 | defer q.mutex.unlock(io); |
| 1353 | return getLocked(q, io, buffer, min, true) catch |err| switch (err) { | 1352 | return q.getLocked(io, buffer, min, true) catch |err| switch (err) { |
| 1354 | error.Canceled => unreachable, | 1353 | error.Canceled => unreachable, |
| 1355 | }; | 1354 | }; |
| 1356 | } | 1355 | } |
| 1357 | | 1356 | |
| 1358 | pub fn getLocked(q: *@This(), io: Io, buffer: []u8, min: usize, uncancelable: bool) Cancelable!usize { | 1357 | fn getLocked(q: *@This(), io: Io, buffer: []u8, min: usize, uncancelable: bool) Cancelable!usize { |
| 1359 | // The ring buffer gets first priority, then data should come from any | 1358 | // The ring buffer gets first priority, then data should come from any |
| 1360 | // queued putters, then finally the ring buffer should be filled with | 1359 | // queued putters, then finally the ring buffer should be filled with |
| 1361 | // data from putters so they can be resumed. | 1360 | // data from putters so they can be resumed. |
| 1362 | | 1361 | |
| 1363 | var remaining = buffer; | 1362 | var remaining = buffer; |
| 1364 | while (true) { | 1363 | if (q.get_index <= q.put_index) { |
| 1365 | if (q.get_index <= q.put_index) { | 1364 | const available = q.buffer[q.get_index..q.put_index]; |
| 1366 | const available = q.buffer[q.get_index..q.put_index]; | 1365 | const copy_len = @min(available.len, remaining.len); |
| | 1366 | @memcpy(remaining[0..copy_len], available[0..copy_len]); |
| | 1367 | q.get_index += copy_len; |
| | 1368 | remaining = remaining[copy_len..]; |
| | 1369 | if (remaining.len == 0) { |
| | 1370 | q.fillRingBufferFromPutters(io); |
| | 1371 | return buffer.len; |
| | 1372 | } |
| | 1373 | } else { |
| | 1374 | { |
| | 1375 | const available = q.buffer[q.get_index..]; |
| 1367 | const copy_len = @min(available.len, remaining.len); | 1376 | const copy_len = @min(available.len, remaining.len); |
| 1368 | @memcpy(remaining[0..copy_len], available[0..copy_len]); | 1377 | @memcpy(remaining[0..copy_len], available[0..copy_len]); |
| 1369 | q.get_index += copy_len; | 1378 | q.get_index += copy_len; |
| 1370 | remaining = remaining[copy_len..]; | 1379 | remaining = remaining[copy_len..]; |
| 1371 | if (remaining.len == 0) return fillRingBufferFromPutters(q, io, buffer.len); | 1380 | if (remaining.len == 0) { |
| 1372 | } else { | 1381 | q.fillRingBufferFromPutters(io); |
| 1373 | { | 1382 | return buffer.len; |
| 1374 | const available = q.buffer[q.get_index..]; | | |
| 1375 | const copy_len = @min(available.len, remaining.len); | | |
| 1376 | @memcpy(remaining[0..copy_len], available[0..copy_len]); | | |
| 1377 | q.get_index += copy_len; | | |
| 1378 | remaining = remaining[copy_len..]; | | |
| 1379 | if (remaining.len == 0) return fillRingBufferFromPutters(q, io, buffer.len); | | |
| 1380 | } | | |
| 1381 | { | | |
| 1382 | const available = q.buffer[0..q.put_index]; | | |
| 1383 | const copy_len = @min(available.len, remaining.len); | | |
| 1384 | @memcpy(remaining[0..copy_len], available[0..copy_len]); | | |
| 1385 | q.get_index = copy_len; | | |
| 1386 | remaining = remaining[copy_len..]; | | |
| 1387 | if (remaining.len == 0) return fillRingBufferFromPutters(q, io, buffer.len); | | |
| 1388 | } | 1383 | } |
| 1389 | } | 1384 | } |
| 1390 | // Copy directly from putters into buffer. | 1385 | { |
| 1391 | while (remaining.len > 0) { | 1386 | const available = q.buffer[0..q.put_index]; |
| 1392 | const putter: *Put = @alignCast(@fieldParentPtr("node", q.putters.popFirst() orelse break)); | 1387 | const copy_len = @min(available.len, remaining.len); |
| 1393 | const copy_len = @min(putter.remaining.len, remaining.len); | 1388 | @memcpy(remaining[0..copy_len], available[0..copy_len]); |
| 1394 | @memcpy(remaining[0..copy_len], putter.remaining[0..copy_len]); | 1389 | q.get_index = copy_len; |
| 1395 | putter.remaining = putter.remaining[copy_len..]; | | |
| 1396 | remaining = remaining[copy_len..]; | 1390 | remaining = remaining[copy_len..]; |
| 1397 | if (putter.remaining.len == 0) { | 1391 | if (remaining.len == 0) { |
| 1398 | putter.condition.signal(io); | 1392 | q.fillRingBufferFromPutters(io); |
| 1399 | } else { | 1393 | return buffer.len; |
| 1400 | assert(remaining.len == 0); | | |
| 1401 | q.putters.prepend(&putter.node); | | |
| 1402 | return fillRingBufferFromPutters(q, io, buffer.len); | | |
| 1403 | } | 1394 | } |
| 1404 | } | 1395 | } |
| 1405 | // Both ring buffer and putters queue is empty. | | |
| 1406 | const total_filled = buffer.len - remaining.len; | | |
| 1407 | if (total_filled >= min) return total_filled; | | |
| 1408 | | | |
| 1409 | var pending: Get = .{ .remaining = remaining, .condition = .{}, .node = .{} }; | | |
| 1410 | q.getters.append(&pending.node); | | |
| 1411 | if (uncancelable) | | |
| 1412 | pending.condition.waitUncancelable(io, &q.mutex) | | |
| 1413 | else | | |
| 1414 | try pending.condition.wait(io, &q.mutex); | | |
| 1415 | remaining = pending.remaining; | | |
| 1416 | } | 1396 | } |
| | 1397 | // Copy directly from putters into buffer. |
| | 1398 | while (q.putters.popFirst()) |putter_node| { |
| | 1399 | const putter: *Put = @alignCast(@fieldParentPtr("node", putter_node)); |
| | 1400 | const copy_len = @min(putter.remaining.len, remaining.len); |
| | 1401 | assert(copy_len > 0); |
| | 1402 | @memcpy(remaining[0..copy_len], putter.remaining[0..copy_len]); |
| | 1403 | putter.remaining = putter.remaining[copy_len..]; |
| | 1404 | remaining = remaining[copy_len..]; |
| | 1405 | if (putter.remaining.len == 0) { |
| | 1406 | putter.condition.signal(io); |
| | 1407 | if (remaining.len > 0) continue; |
| | 1408 | } else q.putters.prepend(putter_node); |
| | 1409 | assert(remaining.len == 0); |
| | 1410 | q.fillRingBufferFromPutters(io); |
| | 1411 | return buffer.len; |
| | 1412 | } |
| | 1413 | // Both ring buffer and putters queue is empty. |
| | 1414 | const total_filled = buffer.len - remaining.len; |
| | 1415 | if (total_filled >= min) return total_filled; |
| | 1416 | |
| | 1417 | var pending: Get = .{ .remaining = remaining, .condition = .{}, .node = .{} }; |
| | 1418 | q.getters.append(&pending.node); |
| | 1419 | defer if (pending.remaining.len > 0) q.getters.remove(&pending.node); |
| | 1420 | while (pending.remaining.len > 0) if (uncancelable) |
| | 1421 | pending.condition.waitUncancelable(io, &q.mutex) |
| | 1422 | else |
| | 1423 | try pending.condition.wait(io, &q.mutex); |
| | 1424 | q.fillRingBufferFromPutters(io); |
| | 1425 | return buffer.len; |
| 1417 | } | 1426 | } |
| 1418 | | 1427 | |
| 1419 | /// Called when there is nonzero space available in the ring buffer and | 1428 | /// Called when there is nonzero space available in the ring buffer and |
| 1420 | /// potentially putters waiting. The mutex is already held and the task is | 1429 | /// potentially putters waiting. The mutex is already held and the task is |
| 1421 | /// to copy putter data to the ring buffer and signal any putters whose | 1430 | /// to copy putter data to the ring buffer and signal any putters whose |
| 1422 | /// buffers been fully copied. | 1431 | /// buffers been fully copied. |
| 1423 | fn fillRingBufferFromPutters(q: *TypeErasedQueue, io: Io, len: usize) usize { | 1432 | fn fillRingBufferFromPutters(q: *TypeErasedQueue, io: Io) void { |
| 1424 | while (true) { | 1433 | while (q.putters.popFirst()) |putter_node| { |
| 1425 | const putter: *Put = @alignCast(@fieldParentPtr("node", q.putters.popFirst() orelse return len)); | 1434 | const putter: *Put = @alignCast(@fieldParentPtr("node", putter_node)); |
| 1426 | const available = q.buffer[q.put_index..]; | 1435 | { |
| 1427 | const copy_len = @min(available.len, putter.remaining.len); | 1436 | const available = q.buffer[q.put_index..]; |
| 1428 | @memcpy(available[0..copy_len], putter.remaining[0..copy_len]); | 1437 | const copy_len = @min(available.len, putter.remaining.len); |
| 1429 | putter.remaining = putter.remaining[copy_len..]; | 1438 | @memcpy(available[0..copy_len], putter.remaining[0..copy_len]); |
| 1430 | q.put_index += copy_len; | 1439 | putter.remaining = putter.remaining[copy_len..]; |
| 1431 | if (putter.remaining.len == 0) { | 1440 | q.put_index += copy_len; |
| 1432 | putter.condition.signal(io); | 1441 | if (putter.remaining.len == 0) { |
| 1433 | continue; | 1442 | putter.condition.signal(io); |
| | 1443 | continue; |
| | 1444 | } |
| 1434 | } | 1445 | } |
| 1435 | const second_available = q.buffer[0..q.get_index]; | 1446 | { |
| 1436 | const second_copy_len = @min(second_available.len, putter.remaining.len); | 1447 | const available = q.buffer[0..q.get_index]; |
| 1437 | @memcpy(second_available[0..second_copy_len], putter.remaining[0..second_copy_len]); | 1448 | const copy_len = @min(available.len, putter.remaining.len); |
| 1438 | putter.remaining = putter.remaining[copy_len..]; | 1449 | @memcpy(available[0..copy_len], putter.remaining[0..copy_len]); |
| 1439 | q.put_index = copy_len; | 1450 | putter.remaining = putter.remaining[copy_len..]; |
| 1440 | if (putter.remaining.len == 0) { | 1451 | q.put_index = copy_len; |
| 1441 | putter.condition.signal(io); | 1452 | if (putter.remaining.len == 0) { |
| 1442 | continue; | 1453 | putter.condition.signal(io); |
| | 1454 | continue; |
| | 1455 | } |
| 1443 | } | 1456 | } |
| 1444 | q.putters.prepend(&putter.node); | 1457 | q.putters.prepend(putter_node); |
| 1445 | return len; | 1458 | break; |
| 1446 | } | 1459 | } |
| 1447 | } | 1460 | } |
| 1448 | }; | 1461 | }; |