_allocate_display released the host-wide flock as soon as it picked a
number, but Xvnc writes /tmp/.X<n>-lock only once it is up. Two profiles
cold-starting together both picked n; the loser's Xvnc failed and its
launcher's stale-lock cleanup could unlink the winner's socket. There was
also no per-profile lock at all: two start() calls for one profile
spawned two launchers, the second overwrote launcher.pid and the first was
orphaned.
start() now takes <state_dir>/start.lock (per profile) around the
running-check, and the allocation lock around pick + spawn + publish
wait (bounded by wait_seconds, default 15s, so a stuck launcher cannot
wedge other profiles for long). stop() takes the same per-profile lock so
a stop cannot interleave with a start. The launcher does not inherit the
lock fds (close_fds=True), so the locks fall with the caller.
(cherry picked from commit 1eee1a331e7ac6a8a2860dd7ff2df0150fe12a8b)