【发布时间】:2021-07-13 13:22:49
【问题描述】:
我有一些需要 X11 显示的单元测试,所以我计划在运行它们之前启动 Xvfb,但是要启动 Xvfb,我需要一个空闲的显示编号来连接它。我最好的猜测是查看/tmp/.X11-unix 中的免费内容,但如果许多测试尝试同时开始,我不确定如何处理比赛。
sshd 必须这样做,有人知道怎么做吗?
【问题讨论】:
标签: x11
我有一些需要 X11 显示的单元测试,所以我计划在运行它们之前启动 Xvfb,但是要启动 Xvfb,我需要一个空闲的显示编号来连接它。我最好的猜测是查看/tmp/.X11-unix 中的免费内容,但如果许多测试尝试同时开始,我不确定如何处理比赛。
sshd 必须这样做,有人知道怎么做吗?
【问题讨论】:
标签: x11
感谢this answer 相关问题How high do X11 display numbers go?:
最近的 X 服务器 1.13 版(Xvfb,也是)支持-displayfd <fd> 命令行选项:它将使 X 服务器自己选择显示器并将显示器编号写回文件描述符 <fd>。这有点令人费解,但这是要求Xvfb 使用任何免费显示的安全且无竞争条件的方式。一个bash 的例子:
exec 6>display.log
Xvfb -displayfd 6
# The display number of the new Xvfb instance has been written to display.log
# Kill Xvfb
exec 6>&-
【讨论】:
Xvfb v1.14 在 jessie 中可用,这意味着平均发行版应该是相当新的(2013 年下半年或之后)。
为什么不利用每个 X11 服务器都将“锁定”文件放入 /tmp 的事实?
这称为/tmp/.Xn-lock,其中“n”是显示ID。 (还要注意文件名中的前导 .)。
这是 Xserver 本身用来检查重复的机制,它似乎在我尝试过的所有 *nix 平台(HP-UX、Linux、...)上都是一致的
所以你可以调整你的脚本(请原谅我的语法错误,我不习惯 C shell 而不是 Bourne/Korn shell 脚本)
DISPLAY_NUM=0
do
if ( -e /tmp/.X$DISPLAY_NUM-lock ) then
let DISPLAY_NUM=$DISPLAY_NUM+1
else
Xvfb :$DISPLAY_NUM -screen 0 1280x1024x24 -ac (or whatever args take your fancy)
fi
done
【讨论】:
试图找到一个免费的显示号码是没有意义的。正如您已经猜到的,在您找到一个空闲端口和 Xvfb 启动之间,另一台 X 服务器可能占用了您认为空闲的端口。因此,最好尝试启动 Xvfb,如果端口被占用,则处理失败,然后在下一个端口重试,直到成功或用完端口尝试。
#!/bin/bash
DISPLAY_NUM=0
unset TEST_HAS_RUN
until [ $TEST_HAS_RUN ] || (( $DISPLAY_NUM > 10 ))
do
Xvfb :$DISPLAY_NUM &
jobs
sleep 2 # assumption here is that Xvfb will exit quickly if it can't launch
if jobs | grep Xvfb
then
echo launching test on :$DISPLAY_NUM
xterm -display :$DISPLAY_NUM
TEST_HAS_RUN=1
kill %-
else
let DISPLAY_NUM=$DISPLAY_NUM+1
fi
done
【讨论】:
xterm 启动成功,在用户手动退出之前它不会阻塞你的脚本吗?否则看起来TEST_HAS_RUN 永远不会被设置,并且循环永远不会退出。事实上,如果xterm 启动失败,您的测试似乎通过。我错过了什么吗?
-fbdir /var/tmp/$0.$$.$RANDOM)启动 Xvfb,然后在该目录中检查文件 Xvfb_screen0。
可能有点跑题了,但是如果您使用 xvfb-run 来启动需要 Xserver 的命令,那么只需运行
# xvfb-run -a your command
成功了。
【讨论】:
基于@karunski 的回答。
在Xvfb进程中使用Xvfb探测显示器,使用lsof检查是否是unix套接字,更有效,注意sleep 0.5,可以根据机器变化。
#!/bin/bash
DISPLAY=0
until [ $DISPLAY_NUM > 10 ]; do
echo -n "Looking for display on $DISPLAY..."
Xvfb :$DISPLAY > /dev/null 2>&1 &
pid=$!
sleep 0.5
lsof -a -U -p $pid > /dev/null 2>&1
notfound="$?"
kill $pid > /dev/null 2>&1
wait $pid
[ "$notfound" == "0" ] && echo "found" && break
echo "fail"
let DISPLAY=DISPLAY+1
done
【讨论】:
这对我有用(注意 - 使用 bash)
exec {lock_fd}>/var/lock/xlockfile || exit 1
flock "$lock_fd" || { echo "ERROR: flock() failed." >&2; exit 1; }
DISPLAY_NUM=1
until [[ $xvfb ]]; do
if [[ -e /tmp/.X$DISPLAY_NUM-lock ]]; then
let DISPLAY_NUM=$DISPLAY_NUM+1
else
Xvfb :$DISPLAY_NUM -ac -screen 0 $XVFB_WHD -nolisten tcp &
xvfb=$!
fi
done
flock -u "$lock_fd"
请注意,外向锁只有在所有运行 xvfb 命令的脚本都使用它时才有效,否则你会再次遇到竞争条件
【讨论】: