mirror of
https://github.com/tmux/tmux.git
synced 2026-10-06 17:49:52 +00:00
165 lines
4.1 KiB
Bash
165 lines
4.1 KiB
Bash
#!/bin/sh
|
|
|
|
# A disconnected waiter must release both its wait and its command queue.
|
|
PATH=/bin:/usr/bin
|
|
TERM=screen
|
|
export TERM
|
|
|
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
|
OUT=$(mktemp -d)
|
|
TMUX="$TEST_TMUX -S$OUT/socket -f/dev/null"
|
|
pids=
|
|
|
|
cleanup()
|
|
{
|
|
for pid in $pids; do
|
|
kill "$pid" 2>/dev/null || true
|
|
done
|
|
$TMUX kill-server 2>/dev/null || true
|
|
rm -rf "$OUT"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
fail()
|
|
{
|
|
echo "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
wait_list()
|
|
{
|
|
expected=$1
|
|
shift
|
|
i=0
|
|
while [ $i -lt 100 ]; do
|
|
value=$($TMUX wait-for -l "$@") || fail "list waiters failed"
|
|
[ "$value" = "$expected" ] && return
|
|
i=$((i + 1))
|
|
sleep 0.05
|
|
done
|
|
fail "expected waiters '$expected', got '$value'"
|
|
}
|
|
|
|
wait_free()
|
|
{
|
|
client_pid=$1
|
|
i=0
|
|
while [ $i -lt 100 ]; do
|
|
awk -v pid="$client_pid" '
|
|
$4 == "IDENTIFY_CLIENTPID" && $5 == pid { address = $3 }
|
|
address != "" && $2 == "free" && $3 == "client" &&
|
|
$4 == address && $5 == "(0" { freed = 1 }
|
|
END { exit !freed }
|
|
' "$OUT"/tmux-server-*.log && return
|
|
i=$((i + 1))
|
|
sleep 0.05
|
|
done
|
|
fail "client $client_pid was not freed"
|
|
}
|
|
|
|
cd "$OUT" || exit 1
|
|
$TMUX -vv new-session -d -s test || fail "new-session failed"
|
|
$TMUX set -g @continued 0 || fail "set option failed"
|
|
|
|
for signal in TERM KILL; do
|
|
for kind in channel lock event; do
|
|
name="$kind-$signal"
|
|
case $kind in
|
|
channel) args="$name"; list_args="$name" ;;
|
|
lock)
|
|
$TMUX wait-for -L "$name" || fail "lock failed"
|
|
args="-L $name"; list_args="$name"
|
|
;;
|
|
event) args="-E @$name"; list_args="-E @$name" ;;
|
|
esac
|
|
|
|
$TMUX wait-for $args \; set -g @continued 1 &
|
|
dead=$!
|
|
pids="$dead"
|
|
wait_list "client-$dead" $list_args
|
|
|
|
$TMUX wait-for $args &
|
|
live=$!
|
|
pids="$dead $live"
|
|
wait_list "$(printf 'client-%s\nclient-%s' "$dead" "$live")" \
|
|
$list_args
|
|
|
|
kill -"$signal" "$dead" || fail "kill failed"
|
|
wait "$dead" 2>/dev/null || true
|
|
pids="$live"
|
|
wait_list "client-$live" $list_args
|
|
wait_free "$dead"
|
|
[ "$($TMUX show -gqv @continued)" = 0 ] ||
|
|
fail "disconnected client's next command ran"
|
|
|
|
case $kind in
|
|
channel) $TMUX wait-for -S "$name" || fail "signal failed" ;;
|
|
lock) $TMUX wait-for -U "$name" || fail "unlock failed" ;;
|
|
event)
|
|
$TMUX wait-for -E -w "client-$live" "@$name" ||
|
|
fail "wake event waiter failed"
|
|
;;
|
|
esac
|
|
wait_list "" $list_args
|
|
wait_free "$live"
|
|
wait "$live" || fail "surviving waiter failed"
|
|
pids=
|
|
if [ "$kind" = lock ]; then
|
|
$TMUX wait-for -U "$name" || fail "final unlock failed"
|
|
fi
|
|
done
|
|
done
|
|
|
|
# Removing the last waiter must remove its otherwise unused channel, and must
|
|
# not create a pending signal. Unrelated pending signals must be preserved.
|
|
$TMUX wait-for -S saved || fail "save signal failed"
|
|
$TMUX wait-for last &
|
|
dead=$!
|
|
pids="$dead"
|
|
wait_list "client-$dead" last
|
|
kill -KILL "$dead" || fail "kill last waiter failed"
|
|
wait "$dead" 2>/dev/null || true
|
|
pids=
|
|
wait_list "" last
|
|
wait_free "$dead"
|
|
grep -F 'remove empty wait channel last' "$OUT"/tmux-server-*.log \
|
|
>/dev/null || fail "empty channel was not removed"
|
|
|
|
$TMUX wait-for saved \; wait-for last &
|
|
live=$!
|
|
pids="$live"
|
|
wait_list "client-$live" last
|
|
$TMUX wait-for -S last || fail "signal last failed"
|
|
wait_free "$live"
|
|
wait "$live" || fail "pending signal was not preserved"
|
|
pids=
|
|
|
|
# Source-file leaves a cleanup callback behind the blocked command.
|
|
printf 'wait-for sourced\nset -g @continued 1\n' >"$OUT/source.conf"
|
|
$TMUX source-file "$OUT/source.conf" &
|
|
dead=$!
|
|
pids="$dead"
|
|
wait_list "client-$dead" sourced
|
|
kill -KILL "$dead" || fail "kill source-file waiter failed"
|
|
wait "$dead" 2>/dev/null || true
|
|
pids=
|
|
wait_list "" sourced
|
|
wait_free "$dead"
|
|
[ "$($TMUX show -gqv @continued)" = 0 ] ||
|
|
fail "disconnected source-file client's next command ran"
|
|
|
|
# Firing an event after cancellation must not call the removed event sink.
|
|
$TMUX wait-for -E window-renamed &
|
|
dead=$!
|
|
pids="$dead"
|
|
wait_list "client-$dead" -E window-renamed
|
|
kill -KILL "$dead" || fail "kill event waiter failed"
|
|
wait "$dead" 2>/dev/null || true
|
|
pids=
|
|
wait_list "" -E window-renamed
|
|
wait_free "$dead"
|
|
$TMUX rename-window -t test:0 renamed || fail "rename-window failed"
|
|
$TMUX display-message -p '#{pid}' >/dev/null || fail "server exited"
|
|
|
|
exit 0
|