| ... | ... | @@ -69,6 +69,28 @@ const runShell = (script: string) => { |
| 69 | 69 | |
| 70 | 70 | const sh = (value: string) => `'${value.replaceAll("'", "'\\''")}'`; |
| 71 | 71 | |
| 72 | // Polls for up to five seconds until a background holder has taken effect. |
| 73 | const awaitHolder = (condition: string) => |
| 74 | `i=0; until ${condition}; do i=$((i + 1)); [ "$i" -lt 500 ] || exit 1; sleep 0.01; done`; |
| 75 | |
| 76 | // Holds a cache busy the way a running server does: the holder's argv[0] is the |
| 77 | // runtime entry, which the prune and install scripts look for in /proc cmdline. |
| 78 | // It reads a pipe the script keeps open on fd 7, so it exits with the script |
| 79 | // instead of outliving it on a timer. |
| 80 | const holdRuntimeBusy = (entry: string) => |
| 81 | [ |
| 82 | `exec 7> >(exec -a ${entry} cat >/dev/null 2>&1)`, |
| 83 | awaitHolder(`grep -qF -- ${entry} /proc/[0-9]*/cmdline 2>/dev/null`), |
| 84 | ].join("\n"); |
| 85 | |
| 86 | // Holds a cache's install lock the way a concurrent install does, and likewise |
| 87 | // releases it when the script exits. |
| 88 | const holdInstallLock = (lock: string) => |
| 89 | [ |
| 90 | `exec 6> >(exec 9> ${lock}; flock -x 9; cat >/dev/null 2>&1)`, |
| 91 | awaitHolder(`! flock -n ${lock} true`), |
| 92 | ].join("\n"); |
| 93 | |
| 72 | 94 | const readField = (stdout: string, field: string) => { |
| 73 | 95 | const line = stdout.split("\n").find((candidate) => candidate.startsWith(`${field}:`)); |
| 74 | 96 | if (line === undefined) throw new Error(`missing ${field} in fixture output: ${stdout}`); |
| ... | ... | @@ -712,9 +734,7 @@ describe.skipIf(posixShellRunner === null)("WSL runtime install script (executed |
| 712 | 734 | `runtime_root=${sh(fixture.runtimeRoot)}`, |
| 713 | 735 | `runtime_parent=${sh(fixture.runtimeParent)}`, |
| 714 | 736 | 'rm "$runtime_root/.t3code-wsl-runtime-ready"', |
| 715 | | 'sh -c "sleep 30" "$runtime_root/t3" >/dev/null 2>&1 &', |
| 716 | | "active_pid=$!", |
| 717 | | "sleep 0.1", |
| 737 | holdRuntimeBusy('"$runtime_root/t3"'), |
| 718 | 738 | fixture.installScript(), |
| 719 | 739 | 'stale=$(find "$runtime_parent" -maxdepth 1 -type d -name ".sha256-*.stale.*" -print -quit)', |
| 720 | 740 | 'test -n "$stale"', |
| ... | ... | @@ -723,8 +743,6 @@ describe.skipIf(posixShellRunner === null)("WSL runtime install script (executed |
| 723 | 743 | "export HOME", |
| 724 | 744 | buildWslRuntimePruneScript(fixture.runtimeId), |
| 725 | 745 | 'test ! -e "$stale"', |
| 726 | | "kill $active_pid", |
| 727 | | "wait $active_pid 2>/dev/null || true", |
| 728 | 746 | ].join("\n"), |
| 729 | 747 | ); |
| 730 | 748 | |
| ... | ... | @@ -750,15 +768,8 @@ describe.skipIf(posixShellRunner === null)("WSL runtime install script (executed |
| 750 | 768 | 'touch -d "4 minutes ago" "$runtime_parent/sha256-active"', |
| 751 | 769 | 'touch -d "3 minutes ago" "$runtime_parent/sha256-old"', |
| 752 | 770 | 'touch -d "2 minutes ago" "$runtime_parent/sha256-locked"', |
| 753 | | 'sh -c "sleep 30" "$runtime_parent/sha256-active/t3" >/dev/null 2>&1 &', |
| 754 | | "active_pid=$!", |
| 755 | | "(", |
| 756 | | ' exec 9> "$runtime_parent/.sha256-locked.install.lock"', |
| 757 | | " flock -x 9", |
| 758 | | " sleep 30", |
| 759 | | ") >/dev/null 2>&1 &", |
| 760 | | "lock_pid=$!", |
| 761 | | "sleep 0.1", |
| 771 | holdRuntimeBusy('"$runtime_parent/sha256-active/t3"'), |
| 772 | holdInstallLock('"$runtime_parent/.sha256-locked.install.lock"'), |
| 762 | 773 | `HOME="$home"`, |
| 763 | 774 | "export HOME", |
| 764 | 775 | buildWslRuntimePruneScript("sha256-current"), |
| ... | ... | @@ -769,9 +780,6 @@ describe.skipIf(posixShellRunner === null)("WSL runtime install script (executed |
| 769 | 780 | 'test -d "$runtime_parent/versions"', |
| 770 | 781 | 'test ! -e "$runtime_parent/sha256-old"', |
| 771 | 782 | 'test ! -e "$runtime_parent/sha256-markerless"', |
| 772 | | "kill $active_pid $lock_pid", |
| 773 | | "wait $active_pid 2>/dev/null || true", |
| 774 | | "wait $lock_pid 2>/dev/null || true", |
| 775 | 783 | 'rm -rf "$work"', |
| 776 | 784 | ].join("\n"), |
| 777 | 785 | ); |