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