Howto terminate xvfb-run properly
Asked Answered
E

2

7

In order to perform some JavaScript unit tests with karma inside a docker container (based on ubuntu 14.04) I'm starting firefox in the container using a karma-script-launcher with xvfb-run. The start script looks like this:

#!/bin/bash
set -o errexit 

# nasty workaround as xvfb-run doesn't cleanup properly...
trap "pkill -f /usr/lib/firefox/firefox" EXIT

xvfb-run --auto-servernum --server-args='-screen 0, 1024x768x16' firefox $1

Starting the browser and executing the unit tests works very well. After executing the tests karma terminates the spawned browser instance - in my case the script that launched firefox over xvfb-run.

In the above script you can see that I registered a trap to kill the launched firefox on exit of my script. This works, but the script is not a very nice citizen as it terminates all instances of firefox that are currently running instead of just terminating the one instance that was launched by the script. I first tried to kill the xfvb-run process but killing this process has no effect on the sub-process launched by the xvfb-run script...

If I start firefox over xvfb-run manually there is a bunch of spawned processes:

root@1d7a5988e521:/data# xvfb-run --auto-servernum --server-args='-screen 0, 1024x768x16' firefox &
[1] 348
root@1d7a5988e521:/data# ps ax
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 bash
  348 ?        S      0:00 /bin/sh /usr/bin/xvfb-run --auto-servernum --server-args=-screen 0, 1024x768x16 firefox
  360 ?        S      0:00 Xvfb :99 -screen 0, 1024x768x16 -nolisten tcp -auth /tmp/xvfb-run.bgMEuq/Xauthority
  361 ?        Sl     0:00 /usr/lib/firefox/firefox
  378 ?        S      0:00 dbus-launch --autolaunch bcf665e095759bae9fc1929b57455cad --binary-syntax --close-stderr
  379 ?        Ss     0:00 //bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
  388 ?        S      0:00 /usr/lib/x86_64-linux-gnu/gconf/gconfd-2
  414 ?        R+     0:00 ps ax
root@1d7a5988e521:/data#

If I now kill the xvfb-run process (PID 348), only this process will be terminated, leaving the other processes running. If I kill the firefox process (PID 361) instead, the xvfb-run script correctly terminates and kills the other processes as well. But from my script I only know the PID of the xvfb-run process...

During my research I stumbled across this rather old bug report for xvfb-run which still seems to be valid in spite of the bug's status beeing fixed back in 2012.

Is there any polite way to terminate the xvfb-run process in order for the other processes to be cleaned up correctly?

Eye answered 27/5, 2016 at 10:47 Comment(0)
E
4

I posted this question on unix.stackexchange.com some time ago as this is more related to Unix/Linux than to programming in general and did not attract much attention here:

Howto terminate xvfb-run properly @ Unix & Linux

However the only option to terminate the X-programs correclty seems to be the not use xvfb-run and to write your own script to start the processes with Xvfb.

Eye answered 2/11, 2016 at 10:48 Comment(0)
W
1

While on the older side, I ended up coming across this. The link in dpr's post basically says to recreate xvfb-run so that it can do a better job of cleaning up. Because I had some free time, I ended up looking to see if that could be avoided.

What I ended up with is using process groups. xvfb-run doesn't detach Xvfb or the command that it spawns under it, it's still part of the same PGID. For bash, this would mean running in monitoring mode and then doing something like (note the '-' before the PID):

xvfb-run -a blah &
xvfb_pid=$!
kill -- "-$xvfb_pid"

which would kill the whole process group that xvfb-run is the leader of. This only works in monitor mode because only monitor mode will give each background process their own group.

I can't recommend using job control functionality with bash and scripting. What I'd recommend instead is calling setsid:

setsid xvfb-run -a blah &
xvfb_pid=$!
kill -- "-$xvfb_pid"

However, note that it calls setsid which also makes the child process a session leader. This is stronger than a group and may be more than what's wanted (although I can't think of anything it would immediately cause issues with).

I ended up using a C solution that calls setpgid(0,0) in the child instead of setsid() before execing into xvfb-run, and killing the process with killpg.

Welford answered 8/4, 2022 at 16:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.