fix: close demo lifecycle races
This commit is contained in:
+49
-29
@@ -89,28 +89,25 @@ demo_interpreter_for_entry() {
|
||||
else demo_resolve_command "${interpreter[0]}"; fi
|
||||
}
|
||||
|
||||
demo_has_sequence_from() {
|
||||
demo_has_exact_tail() {
|
||||
local array_name=$1 begin=$2
|
||||
local -n argv_ref=$array_name
|
||||
shift 2
|
||||
local -a wanted=("$@")
|
||||
local i j
|
||||
for ((i = begin; i + ${#wanted[@]} <= ${#argv_ref[@]}; i++)); do
|
||||
for ((j = 0; j < ${#wanted[@]}; j++)); do
|
||||
[[ ${argv_ref[i+j]} == "${wanted[j]}" ]] || break
|
||||
done
|
||||
((j == ${#wanted[@]})) && return 0
|
||||
local index
|
||||
((${#argv_ref[@]} - begin == ${#wanted[@]})) || return 1
|
||||
for index in "${!wanted[@]}"; do
|
||||
[[ ${argv_ref[begin+index]} == "${wanted[index]}" ]] || return 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
demo_command_matches() {
|
||||
local root=$1 pid=$2 kind=$3 expected executable interpreter entry_index
|
||||
local -a arguments=()
|
||||
[[ -r "/proc/$pid/cmdline" && -e "/proc/$pid/exe" ]] || return 1
|
||||
mapfile -d '' -t arguments <"/proc/$pid/cmdline"
|
||||
{ mapfile -d '' -t arguments <"/proc/$pid/cmdline"; } 2>/dev/null || return 1
|
||||
((${#arguments[@]} > 0)) || return 1
|
||||
executable=$(readlink -f -- "/proc/$pid/exe") || return 1
|
||||
executable=$(readlink -f -- "/proc/$pid/exe" 2>/dev/null) || return 1
|
||||
|
||||
if [[ "$kind" == anvil ]]; then
|
||||
expected=$(demo_resolve_command anvil) || return 1
|
||||
@@ -128,13 +125,11 @@ demo_command_matches() {
|
||||
fi
|
||||
|
||||
if [[ "$kind" == anvil ]]; then
|
||||
demo_has_sequence_from arguments "$((entry_index + 1))" --host 127.0.0.1 || return 1
|
||||
demo_has_sequence_from arguments "$((entry_index + 1))" --port 8545 || return 1
|
||||
demo_has_sequence_from arguments "$((entry_index + 1))" --chain-id 31337 || return 1
|
||||
local dev_phrase='test test test test test test test test test test test junk'
|
||||
demo_has_exact_tail arguments "$((entry_index + 1))" \
|
||||
--host 127.0.0.1 --port 8545 --chain-id 31337 --mnemonic "$dev_phrase"
|
||||
else
|
||||
local -a expected_tail=(web --host 127.0.0.1 --port 5173)
|
||||
local -a actual_tail=("${arguments[@]:entry_index+1}")
|
||||
[[ "${actual_tail[*]}" == "${expected_tail[*]}" && ${#actual_tail[@]} -eq ${#expected_tail[@]} ]] || return 1
|
||||
demo_has_exact_tail arguments "$((entry_index + 1))" web --host 127.0.0.1 --port 5173
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -146,10 +141,17 @@ demo_identity_matches() {
|
||||
demo_command_matches "$root" "$pid" "$kind"
|
||||
}
|
||||
|
||||
demo_capture_raw_launch() {
|
||||
local pid=$1 start_name=$2 pgid_name=$3 state raw_actual_start raw_actual_pgid sid
|
||||
demo_read_process_identity "$pid" state raw_actual_start raw_actual_pgid sid || return 1
|
||||
[[ "$state" != Z && "$pid" == "$raw_actual_pgid" && "$pid" == "$sid" ]] || return 1
|
||||
printf -v "$start_name" '%s' "$raw_actual_start"
|
||||
printf -v "$pgid_name" '%s' "$raw_actual_pgid"
|
||||
}
|
||||
|
||||
demo_capture_process() {
|
||||
local root=$1 kind=$2 pid=$3 start_name=$4 pgid_name=$5 state actual_start actual_pgid sid
|
||||
demo_read_process_identity "$pid" state actual_start actual_pgid sid || return 1
|
||||
[[ "$state" != Z && "$pid" == "$actual_pgid" && "$pid" == "$sid" ]] || return 1
|
||||
local root=$1 kind=$2 pid=$3 start_name=$4 pgid_name=$5 actual_start actual_pgid
|
||||
demo_capture_raw_launch "$pid" actual_start actual_pgid || return 1
|
||||
demo_command_matches "$root" "$pid" "$kind" || return 1
|
||||
printf -v "$start_name" '%s' "$actual_start"
|
||||
printf -v "$pgid_name" '%s' "$actual_pgid"
|
||||
@@ -201,20 +203,29 @@ demo_collect_group_members() {
|
||||
}
|
||||
|
||||
demo_anchor_allows_signal() {
|
||||
local root=$1 kind=$2 leader=$3 expected_start=$4 expected_pgid=$5 state start pgid sid
|
||||
local root=$1 kind=$2 leader=$3 expected_start=$4 expected_pgid=$5 identity_mode=${6:-validated} state start pgid sid
|
||||
if ! demo_read_process_identity "$leader" state start pgid sid; then return 0; fi
|
||||
[[ "$start" == "$expected_start" && "$pgid" == "$expected_pgid" && "$sid" == "$expected_pgid" ]] || return 1
|
||||
[[ "$state" == Z ]] && return 0
|
||||
[[ "$identity_mode" == raw ]] && return 0
|
||||
demo_process_has_command_line "$leader" || return 0
|
||||
demo_command_matches "$root" "$leader" "$kind"
|
||||
if demo_command_matches "$root" "$leader" "$kind"; then return 0; fi
|
||||
if ! demo_read_process_identity "$leader" state start pgid sid; then return 0; fi
|
||||
[[ "$state" == Z ]] && return 0
|
||||
[[ "$start" == "$expected_start" && "$pgid" == "$expected_pgid" && "$sid" == "$expected_pgid" ]] || return 1
|
||||
return 1
|
||||
}
|
||||
|
||||
demo_signal_member() {
|
||||
local pid=$1 expected_start=$2 expected_pgid=$3 expected_sid=$4 signal=$5 state start pgid sid
|
||||
local pid=$1 expected_start=$2 expected_pgid=$3 expected_sid=$4 signal=$5 state start pgid sid signal_status
|
||||
if ! demo_read_process_identity "$pid" state start pgid sid; then return 0; fi
|
||||
[[ "$state" != Z ]] || return 0
|
||||
[[ "$start" == "$expected_start" && "$pgid" == "$expected_pgid" && "$sid" == "$expected_sid" ]] || return 2
|
||||
kill -"$signal" -- "$pid"
|
||||
if kill -"$signal" -- "$pid"; then return 0; else signal_status=$?; fi
|
||||
if ! demo_read_process_identity "$pid" state start pgid sid; then return 0; fi
|
||||
[[ "$state" != Z ]] || return 0
|
||||
[[ "$start" == "$expected_start" && "$pgid" == "$expected_pgid" && "$sid" == "$expected_sid" ]] || return 0
|
||||
return "$signal_status"
|
||||
}
|
||||
|
||||
demo_group_has_live_members() {
|
||||
@@ -224,12 +235,13 @@ demo_group_has_live_members() {
|
||||
((${#members[@]} > 0))
|
||||
}
|
||||
|
||||
demo_stop_launch() {
|
||||
local root=$1 kind=$2 leader=$3 expected_start=$4 expected_pgid=$5 member member_pid member_start result
|
||||
demo_stop_owned_session() {
|
||||
local root=$1 kind=$2 leader=$3 expected_start=$4 expected_pgid=$5 identity_mode=$6 member member_pid member_start result
|
||||
local -a members
|
||||
[[ "$identity_mode" == validated || "$identity_mode" == raw ]] || return 1
|
||||
demo_is_process_id "$leader" && demo_is_uint "$expected_start" && demo_is_process_id "$expected_pgid" \
|
||||
&& [[ "$leader" == "$expected_pgid" ]] || return 1
|
||||
demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" || {
|
||||
demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" "$identity_mode" || {
|
||||
printf 'Refusing %s PID %s: process identity changed\n' "$kind" "$leader" >&2
|
||||
return 1
|
||||
}
|
||||
@@ -243,13 +255,13 @@ demo_stop_launch() {
|
||||
for member in "${members[@]}"; do
|
||||
IFS=: read -r member_pid member_start <<<"$member"
|
||||
[[ "$member_pid" != "$leader" ]] || continue
|
||||
demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" || return 1
|
||||
demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" "$identity_mode" || return 1
|
||||
demo_signal_member "$member_pid" "$member_start" "$expected_pgid" "$expected_pgid" TERM || return 1
|
||||
done
|
||||
for member in "${members[@]}"; do
|
||||
IFS=: read -r member_pid member_start <<<"$member"
|
||||
[[ "$member_pid" == "$leader" ]] || continue
|
||||
demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" || return 1
|
||||
demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" "$identity_mode" || return 1
|
||||
demo_signal_member "$member_pid" "$member_start" "$expected_pgid" "$expected_pgid" TERM || return 1
|
||||
done
|
||||
for ((result = 0; result < ${DEMO_TERM_WAIT_ATTEMPTS:-50}; result++)); do
|
||||
@@ -264,7 +276,7 @@ demo_stop_launch() {
|
||||
((${#members[@]} > 0)) || break
|
||||
for member in "${members[@]}"; do
|
||||
IFS=: read -r member_pid member_start <<<"$member"
|
||||
if ! demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid"; then
|
||||
if ! demo_anchor_allows_signal "$root" "$kind" "$leader" "$expected_start" "$expected_pgid" "$identity_mode"; then
|
||||
printf 'Refusing KILL escalation: %s leader identity changed\n' "$kind" >&2
|
||||
return 1
|
||||
fi
|
||||
@@ -287,6 +299,14 @@ demo_stop_launch() {
|
||||
demo_remove_record "$root" "$kind"
|
||||
}
|
||||
|
||||
demo_stop_launch() {
|
||||
demo_stop_owned_session "$1" "$2" "$3" "$4" "$5" validated
|
||||
}
|
||||
|
||||
demo_stop_raw_launch() {
|
||||
demo_stop_owned_session "$1" "$2" "$3" "$4" "$5" raw
|
||||
}
|
||||
|
||||
demo_stop_recorded() {
|
||||
local root=$1 kind=$2 pid start pgid
|
||||
local pid_path="$root/.demo/$kind.pid" start_path="$root/.demo/$kind.start" pgid_path="$root/.demo/$kind.pgid"
|
||||
|
||||
Reference in New Issue
Block a user