|
11 | 11 |
|
12 | 12 | set -euo pipefail |
13 | 13 |
|
| 14 | +# Resolve the fixed macOS system tools (uname, xcrun, sysctl, ps, id, …) |
| 15 | +# from the real system bin dirs regardless of a poisoned inbound $PATH. |
| 16 | +# The original PATH is appended so user-installed build tools (cmake, |
| 17 | +# ninja) still resolve. |
| 18 | +export PATH="/usr/bin:/bin:/usr/sbin:/sbin:${PATH}" |
| 19 | + |
14 | 20 | if [[ $# -ne 4 ]]; then |
15 | 21 | echo "usage: $0 <mlx-src-dir> <mlx-version> <jit 0|1> <install-prefix>" >&2 |
16 | 22 | exit 2 |
|
70 | 76 | # |
71 | 77 | # `flock(1)` isn't shipped on macOS, so we use atomic `mkdir` as the |
72 | 78 | # lock primitive. The lock dir is keyed on PREFIX, which both |
73 | | -# contexts share. A PID file inside lets us reclaim a stale lock if |
74 | | -# the previous holder died without cleanup. |
| 79 | +# contexts share. A token file (PID + process start time) inside lets |
| 80 | +# us reclaim a stale lock if the previous holder died without cleanup — |
| 81 | +# the start time guards against PID reuse, so a recycled PID belonging |
| 82 | +# to an unrelated live process is still treated as stale. |
75 | 83 | BUILD_DIR="${PREFIX}.build" |
76 | 84 | STAGING="${PREFIX}.staging" |
77 | 85 | LOCK_DIR="${PREFIX}.lock" |
@@ -101,24 +109,46 @@ cleanup() { |
101 | 109 | } |
102 | 110 | trap cleanup EXIT |
103 | 111 |
|
| 112 | +# Record the lock holder as "PID\n<process start time>". A recycled PID |
| 113 | +# (same number, different process) has a different start time, so the |
| 114 | +# stale-lock reclaim below can't mistake an unrelated live process for |
| 115 | +# the original holder — `kill -0` alone can't tell them apart. |
| 116 | +write_lock_token() { |
| 117 | + { echo "$$"; ps -o lstart= -p "$$" 2>/dev/null; } > "$LOCK_PID_FILE" |
| 118 | +} |
| 119 | + |
| 120 | +# Is the recorded holder ($1=pid, $2=start time) still the live process |
| 121 | +# that took the lock? |
| 122 | +holder_is_live() { |
| 123 | + local pid="$1" started="$2" |
| 124 | + [[ -n "$pid" ]] || return 1 |
| 125 | + kill -0 "$pid" 2>/dev/null || return 1 |
| 126 | + local now |
| 127 | + now=$(ps -o lstart= -p "$pid" 2>/dev/null || true) |
| 128 | + [[ -n "$now" && "$now" == "$started" ]] |
| 129 | +} |
| 130 | + |
104 | 131 | while :; do |
105 | 132 | if mkdir "$LOCK_DIR" 2>/dev/null; then |
106 | | - echo "$$" > "$LOCK_PID_FILE" |
| 133 | + write_lock_token |
107 | 134 | acquired_lock=1 |
108 | 135 | break |
109 | 136 | fi |
110 | 137 |
|
111 | | - holder="" |
112 | | - [[ -r "$LOCK_PID_FILE" ]] && holder=$(cat "$LOCK_PID_FILE" 2>/dev/null || true) |
| 138 | + holder_pid="" |
| 139 | + holder_started="" |
| 140 | + if [[ -r "$LOCK_PID_FILE" ]]; then |
| 141 | + { IFS= read -r holder_pid; IFS= read -r holder_started; } < "$LOCK_PID_FILE" 2>/dev/null || true |
| 142 | + fi |
113 | 143 |
|
114 | | - if [[ -n "$holder" ]] && ! kill -0 "$holder" 2>/dev/null; then |
115 | | - echo "==> Reclaiming stale MLX-build lock (dead PID $holder)" >&2 |
| 144 | + if [[ -n "$holder_pid" ]] && ! holder_is_live "$holder_pid" "$holder_started"; then |
| 145 | + echo "==> Reclaiming stale MLX-build lock (holder PID ${holder_pid} is gone)" >&2 |
116 | 146 | rm -rf "$LOCK_DIR" |
117 | 147 | continue |
118 | 148 | fi |
119 | 149 |
|
120 | 150 | if (( printed_wait == 0 )); then |
121 | | - echo "==> Waiting for concurrent MLX build${holder:+ (PID $holder)} on ${PREFIX}" >&2 |
| 151 | + echo "==> Waiting for concurrent MLX build${holder_pid:+ (PID $holder_pid)} on ${PREFIX}" >&2 |
122 | 152 | printed_wait=1 |
123 | 153 | fi |
124 | 154 | sleep 1 |
|
0 commit comments