| ... | @@ -472,6 +472,7 @@ const Serialized = struct { | ... | @@ -472,6 +472,7 @@ const Serialized = struct { |
| 472 | | 472 | |
| 473 | fn serialize() Serialized { | 473 | fn serialize() Serialized { |
| 474 | var serialized_len: usize = 0; | 474 | var serialized_len: usize = 0; |
| | 475 | var any_ipc = false; |
| 475 | | 476 | |
| 476 | // Iterate all of the nodes and construct a serializable copy of the state that can be examined | 477 | // Iterate all of the nodes and construct a serializable copy of the state that can be examined |
| 477 | // without atomics. | 478 | // without atomics. |
| ... | @@ -486,6 +487,8 @@ fn serialize() Serialized { | ... | @@ -486,6 +487,8 @@ fn serialize() Serialized { |
| 486 | dest_storage.completed_count = @atomicLoad(u32, &storage_ptr.completed_count, .monotonic); | 487 | dest_storage.completed_count = @atomicLoad(u32, &storage_ptr.completed_count, .monotonic); |
| 487 | dest_storage.estimated_total_count = @atomicLoad(u32, &storage_ptr.estimated_total_count, .monotonic); | 488 | dest_storage.estimated_total_count = @atomicLoad(u32, &storage_ptr.estimated_total_count, .monotonic); |
| 488 | | 489 | |
| | 490 | any_ipc = any_ipc or dest_storage.getIpcFd() != null; |
| | 491 | |
| 489 | const end_parent = @atomicLoad(Node.Parent, parent_ptr, .seq_cst); | 492 | const end_parent = @atomicLoad(Node.Parent, parent_ptr, .seq_cst); |
| 490 | if (begin_parent == end_parent) { | 493 | if (begin_parent == end_parent) { |
| 491 | serialized_node_parents_buffer[serialized_len] = begin_parent; | 494 | serialized_node_parents_buffer[serialized_len] = begin_parent; |
| ... | @@ -508,6 +511,32 @@ fn serialize() Serialized { | ... | @@ -508,6 +511,32 @@ fn serialize() Serialized { |
| 508 | } | 511 | } |
| 509 | | 512 | |
| 510 | // Find nodes which correspond to child processes. | 513 | // Find nodes which correspond to child processes. |
| | 514 | if (any_ipc) |
| | 515 | serialized_len = serializeIpc(serialized_len); |
| | 516 | |
| | 517 | return .{ |
| | 518 | .parents = serialized_node_parents_buffer[0..serialized_len], |
| | 519 | .storage = serialized_node_storage_buffer[0..serialized_len], |
| | 520 | }; |
| | 521 | } |
| | 522 | |
| | 523 | var parents_copy: [default_node_storage_buffer_len]Node.Parent = undefined; |
| | 524 | var storage_copy: [default_node_storage_buffer_len]Node.Storage = undefined; |
| | 525 | |
| | 526 | const SavedMetadata = extern struct { |
| | 527 | start_index: u16, |
| | 528 | nodes_len: u16, |
| | 529 | main_index: u16, |
| | 530 | flags: Flags, |
| | 531 | |
| | 532 | const Flags = enum(u16) { |
| | 533 | saved = std.math.maxInt(u16), |
| | 534 | _, |
| | 535 | }; |
| | 536 | }; |
| | 537 | |
| | 538 | fn serializeIpc(start_serialized_len: usize) usize { |
| | 539 | var serialized_len = start_serialized_len; |
| 511 | var pipe_buf: [4096]u8 align(4) = undefined; | 540 | var pipe_buf: [4096]u8 align(4) = undefined; |
| 512 | | 541 | |
| 513 | for ( | 542 | for ( |
| ... | @@ -532,24 +561,23 @@ fn serialize() Serialized { | ... | @@ -532,24 +561,23 @@ fn serialize() Serialized { |
| 532 | // Ignore all but the last message on the pipe. | 561 | // Ignore all but the last message on the pipe. |
| 533 | var input: []align(2) u8 = pipe_buf[0..bytes_read]; | 562 | var input: []align(2) u8 = pipe_buf[0..bytes_read]; |
| 534 | if (input.len == 0) { | 563 | if (input.len == 0) { |
| 535 | main_storage.completed_count = 0; | 564 | serialized_len = useSavedIpcData(serialized_len, main_storage, main_index); |
| 536 | main_storage.estimated_total_count = 0; | | |
| 537 | continue; | 565 | continue; |
| 538 | } | 566 | } |
| 539 | | 567 | |
| 540 | const storage, const parents = while (true) { | 568 | const storage, const parents = while (true) { |
| 541 | if (input.len < 4) { | 569 | if (input.len < 4) { |
| 542 | std.log.warn("short read: {d} out of 4 header bytes", .{input.len}); | 570 | std.log.warn("short read: {d} out of 4 header bytes", .{input.len}); |
| 543 | main_storage.completed_count = 0; | 571 | // TODO keep track of the short read to trash odd bytes with the next read |
| 544 | main_storage.estimated_total_count = 0; | 572 | serialized_len = useSavedIpcData(serialized_len, main_storage, main_index); |
| 545 | continue; | 573 | continue; |
| 546 | } | 574 | } |
| 547 | const subtree_len = std.mem.readInt(u32, input[0..4], .little); | 575 | const subtree_len = std.mem.readInt(u32, input[0..4], .little); |
| 548 | const expected_bytes = 4 + subtree_len * (@sizeOf(Node.Storage) + @sizeOf(Node.Parent)); | 576 | const expected_bytes = 4 + subtree_len * (@sizeOf(Node.Storage) + @sizeOf(Node.Parent)); |
| 549 | if (input.len < expected_bytes) { | 577 | if (input.len < expected_bytes) { |
| 550 | std.log.warn("short read: {d} out of {d} ({d} nodes)", .{ input.len, expected_bytes, subtree_len }); | 578 | std.log.warn("short read: {d} out of {d} ({d} nodes)", .{ input.len, expected_bytes, subtree_len }); |
| 551 | main_storage.completed_count = 0; | 579 | // TODO keep track of the short read to trash odd bytes with the next read |
| 552 | main_storage.estimated_total_count = 0; | 580 | serialized_len = useSavedIpcData(serialized_len, main_storage, main_index); |
| 553 | continue; | 581 | continue; |
| 554 | } | 582 | } |
| 555 | if (input.len > expected_bytes) { | 583 | if (input.len > expected_bytes) { |
| ... | @@ -564,6 +592,14 @@ fn serialize() Serialized { | ... | @@ -564,6 +592,14 @@ fn serialize() Serialized { |
| 564 | }; | 592 | }; |
| 565 | }; | 593 | }; |
| 566 | | 594 | |
| | 595 | // Remember in case the pipe is empty on next update. |
| | 596 | @as(*SavedMetadata, @ptrCast(&main_storage.name)).* = .{ |
| | 597 | .start_index = @intCast(serialized_len), |
| | 598 | .nodes_len = @intCast(parents.len), |
| | 599 | .main_index = @intCast(main_index), |
| | 600 | .flags = .saved, |
| | 601 | }; |
| | 602 | |
| 567 | // Mount the root here. | 603 | // Mount the root here. |
| 568 | main_storage.* = storage[0]; | 604 | main_storage.* = storage[0]; |
| 569 | | 605 | |
| ... | @@ -580,6 +616,7 @@ fn serialize() Serialized { | ... | @@ -580,6 +616,7 @@ fn serialize() Serialized { |
| 580 | // Root node is being mounted here. | 616 | // Root node is being mounted here. |
| 581 | @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index), | 617 | @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index), |
| 582 | // Other nodes mounted at the end. | 618 | // Other nodes mounted at the end. |
| | 619 | // TODO check for bad data pointing outside the expected range |
| 583 | _ => |off| @enumFromInt(serialized_len + @intFromEnum(off) - 1), | 620 | _ => |off| @enumFromInt(serialized_len + @intFromEnum(off) - 1), |
| 584 | }; | 621 | }; |
| 585 | } | 622 | } |
| ... | @@ -587,10 +624,43 @@ fn serialize() Serialized { | ... | @@ -587,10 +624,43 @@ fn serialize() Serialized { |
| 587 | serialized_len += storage.len - 1; | 624 | serialized_len += storage.len - 1; |
| 588 | } | 625 | } |
| 589 | | 626 | |
| 590 | return .{ | 627 | // Save a copy in case any pipes are empty on the next update. |
| 591 | .parents = serialized_node_parents_buffer[0..serialized_len], | 628 | @memcpy(parents_copy[0..serialized_len], serialized_node_parents_buffer[0..serialized_len]); |
| 592 | .storage = serialized_node_storage_buffer[0..serialized_len], | 629 | @memcpy(storage_copy[0..serialized_len], serialized_node_storage_buffer[0..serialized_len]); |
| 593 | }; | 630 | |
| | 631 | return serialized_len; |
| | 632 | } |
| | 633 | |
| | 634 | fn useSavedIpcData(start_serialized_len: usize, main_storage: *Node.Storage, main_index: usize) usize { |
| | 635 | const saved_metadata: *SavedMetadata = @ptrCast(&main_storage.name); |
| | 636 | if (saved_metadata.flags != .saved) { |
| | 637 | main_storage.completed_count = 0; |
| | 638 | main_storage.estimated_total_count = 0; |
| | 639 | return start_serialized_len; |
| | 640 | } |
| | 641 | |
| | 642 | const start_index = saved_metadata.start_index; |
| | 643 | const nodes_len = saved_metadata.nodes_len; |
| | 644 | const old_main_index = saved_metadata.main_index; |
| | 645 | |
| | 646 | const parents = parents_copy[start_index..][0 .. nodes_len - 1]; |
| | 647 | const storage = storage_copy[start_index..][0 .. nodes_len - 1]; |
| | 648 | |
| | 649 | main_storage.* = storage_copy[old_main_index]; |
| | 650 | |
| | 651 | @memcpy(serialized_node_storage_buffer[start_serialized_len..][0..storage.len], storage); |
| | 652 | |
| | 653 | for (serialized_node_parents_buffer[start_serialized_len..][0..parents.len], parents) |*dest, p| { |
| | 654 | dest.* = switch (p) { |
| | 655 | .none, .unused => .none, |
| | 656 | _ => |prev| @enumFromInt(if (@intFromEnum(prev) == old_main_index) |
| | 657 | main_index |
| | 658 | else |
| | 659 | @intFromEnum(prev) - start_index + start_serialized_len), |
| | 660 | }; |
| | 661 | } |
| | 662 | |
| | 663 | return start_serialized_len + storage.len; |
| 594 | } | 664 | } |
| 595 | | 665 | |
| 596 | fn computeRedraw() []u8 { | 666 | fn computeRedraw() []u8 { |