<NME> xserver.rs
<BEF> /*
 * Steps of XWayland server creation
 *
 * Sockets to create:
 * - a pair for XWayland to connect to smithay as a wayland client, we use our
 *   end to insert the XWayland client in the display
 * - a pair for smithay to connect to XWayland as a WM, we give our end to the
 *   WM and it deals with it
 * - 2 listening sockets on which the XWayland server will listen. We need to
 *   bind them ourselves so we know what value put in the $DISPLAY env variable.
 *   This involves some dance with a lockfile to ensure there is no collision with
 *   an other starting xserver
 *   if we listen on display $D, their paths are respectively:
 *   - /tmp/.X11-unix/X$D
 *   - @/tmp/.X11-unix/X$D (abstract socket)
 *
 * The XWayland server is spawned via an intermediate shell
 * -> wlroots does a double-fork while weston a single one, why ??
 *    -> https://stackoverflow.com/questions/881388/
 * -> once it is started, it will check if SIGUSR1 is set to ignored. If so,
 *    if will consider its parent as "smart", and send a SIGUSR1 signal when
 *    startup completes. We want to catch this so we can launch the VM.
 * -> we need to track if the XWayland crashes, to restart it
 *
 * cf https://github.com/swaywm/wlroots/blob/master/xwayland/xwayland.c
 *
 * Setting SIGUSR1 handler is complicated in multithreaded program, because
 * Xwayland will send SIGUSR1 to the process, and if a thread cannot handle
 * SIGUSR1, that thread will be killed.
 *
 * Double-fork can tackle this issue, but this is also very complex in a
 * a multithread program, after forking only signal-safe functions can be used.
 * The only workaround is to fork early before any other thread starts, but
 * doing so will expose an unsafe interface.
 *
 * We use an intermediate shell to translate the signal to simple fd IO.
    sync::Arc,
};

use calloop::{
    signals::{Signal, Signals},
    LoopHandle, Source,
};

use nix::{
    errno::Errno,
    io::{self, Read},
    os::unix::{
        io::{AsRawFd, RawFd},
        net::UnixStream,
        process::CommandExt,
    },
    process::{ChildStdout, Command, Stdio},
    sync::{Arc, Mutex},
};

use calloop::{
    channel::{self, sync_channel, Channel, SyncSender},
    generic::Generic,
    Interest, LoopHandle, Mode,
};
use wayland_server::{
    backend::{ClientData, ClientId, DisconnectReason},
    Client, DisplayHandle,
};

use slog::{error, info, o};

use super::x11_sockets::{prepare_x11_sockets, X11Lock};

/// The XWayland handle
#[derive(Debug)]
pub struct XWayland {
    inner: Arc<Mutex<Inner>>,
}

/// Events generated by the XWayland manager
///
/// This is a very low-level interface, only notifying you when the connection
/// with XWayland is up, or when it terminates.
///
/// Your WM code must be able to handle the XWayland server connecting then
/// disconnecting several time in a row, but only a single connection will
/// be active at any given time.
#[derive(Debug)]
#[must_use = "Connection events must be handled to prevent fd leaking"]
pub enum XWaylandEvent {
    /// The XWayland server is ready
    Ready {
        /// Privileged X11 connection to XWayland
        connection: UnixStream,

        /// Wayland client representing XWayland
        client: Client,
                let handle = handle.clone();
                Box::new(move |source| handle.kill(source))
            },
            source_maker: Box::new(move |inner| {
                handle
                    .insert_source(
                        Signals::new(&[Signal::SIGUSR1]).map_err(|_| ())?,
                        move |evt, _, _| {
                            debug_assert!(evt.signal() == Signal::SIGUSR1);
                            xwayland_ready(&inner);
                        },
                    )
                    .map_err(|_| ())
    Exited,
}

impl XWayland {
    /// Create a new XWayland manager
    ///
    /// This function returns both the [`XWayland`] handle and an [`XWaylandSource`] that needs to be inserted
    /// into the [`calloop`] event loop, producing the Xwayland startup and shutdown events.
    pub fn new<L>(logger: L, dh: &DisplayHandle) -> (XWayland, XWaylandSource)
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);
        // We don't expect to ever have more than 2 messages in flight, if XWayland got ready and then died right away
        let (sender, channel) = sync_channel(2);
        let inner = Arc::new(Mutex::new(Inner {
struct XWaylandInstance {
    display_lock: X11Lock,
    wayland_client: Client,
    sigusr1_handler: Option<Source<Signals>>,
    wm_fd: Option<UnixStream>,
    started_at: ::std::time::Instant,
    child_pid: Option<Pid>,
}

type SourceMaker<WM> = dyn FnMut(Rc<RefCell<Inner<WM>>>) -> Result<Source<Signals>, ()>;

// Inner implementation of the XWayland manager
struct Inner<WM: XWindowManager> {
    ///
    source_maker: Box<SourceMaker<WM>>,
    wayland_display: Rc<RefCell<Display>>,
    instance: Option<XWaylandInstance>,
    kill_source: Box<dyn Fn(Source<Signals>)>,
    log: ::slog::Logger,
}

    ///
    /// Does nothing if it was not already running, otherwise kills it and you will
    /// later receive a `XWaylandEvent::Exited` event.
    pub fn shutdown(&self) {
        self.inner.lock().unwrap().shutdown();
    }
}

impl Drop for XWayland {
    fn drop(&mut self) {
        self.inner.lock().unwrap().shutdown();

    info!(guard.log, "Starting XWayland");

    let (x_wm_x11, x_wm_me) = UnixStream::pair().map_err(|_| ())?;
    let (wl_x11, wl_me) = UnixStream::pair().map_err(|_| ())?;

    wayland_client_fd: RawFd,
    wm_fd: Option<UnixStream>,
    child_stdout: ChildStdout,
}

// Inner implementation of the XWayland manager
#[derive(Debug)]
struct Inner {
    sender: SyncSender<XWaylandEvent>,
    instance: Option<XWaylandInstance>,
    dh: DisplayHandle,
    log: ::slog::Logger,
}

struct XWaylandClientData {
    inner: Arc<Mutex<Inner>>,
        client_destroy::<WM, T>(&e, data.get().unwrap())
    }));

    // setup the SIGUSR1 handler
    let sigusr1_handler = (&mut *guard.source_maker)(inner.clone())?;

    // all is ready, we can do the fork dance
    let child_pid = match unsafe { fork() } {
        Ok(ForkResult::Parent { child }) => {
        // a shutdown. This will definitely be the case when the compositor exits
        // and the XWayland instance is dropped.
        }
        Ok(ForkResult::Child) => {
            // we are the first child
            let ppid = Pid::parent();
            let mut set = signal::SigSet::empty();
            set.add(signal::Signal::SIGUSR1);
            set.add(signal::Signal::SIGCHLD);
// Launch an XWayland server
            let _ = signal::sigprocmask(signal::SigmaskHow::SIG_BLOCK, Some(&set), None);
            match unsafe { fork() } {
                Ok(ForkResult::Parent { child }) => {
                    // we are still the first child
                    let sig = set.wait();
                    // send USR1 to parent
                    let _ = signal::kill(ppid, signal::Signal::SIGUSR1);
                    // Parent will wait for us and know from out
                    // exit status if XWayland launch was a success or not =)
                    if let Ok(signal::Signal::SIGCHLD) = sig {
    }

    info!(guard.log, "Starting XWayland");

    let (x_wm_x11, x_wm_me) = UnixStream::pair()?;
    let (wl_x11, wl_me) = UnixStream::pair()?;

    let (lock, x_fds) = prepare_x11_sockets(guard.log.clone())?;

    // we have now created all the required sockets

    // all is ready, we can do the fork dance
    let child_stdout = match spawn_xwayland(lock.display(), wl_x11, x_wm_x11, &x_fds) {
        Ok(child_stdout) => child_stdout,
        Err(e) => {
            error!(guard.log, "XWayland failed to spawn"; "err" => format!("{:?}", e));
            return Err(e);
        }
    };

    let loop_inner = inner.clone();
    loop_handle
        .insert_source(
            Generic::<_, io::Error>::new(child_stdout.as_raw_fd(), Interest::READ, Mode::Level),
            move |_, _, _| {
                // the closure must be called exactly one time, this cannot panic
                xwayland_ready(&loop_inner);
        }
    };

    guard.instance = Some(XWaylandInstance {
        display_lock: lock,
        wayland_client: client,
        sigusr1_handler: Some(sigusr1_handler),
        wm_fd: Some(x_wm_me),
        started_at: creation_time,
        child_pid: Some(child_pid),
        child_stdout,
    });

    Ok(())
}

/// An event source for monitoring XWayland status
///
/// You need to insert it in a [`calloop`] event loop to handle the events it produces,
/// of type [`XWaylandEvent`], which notify you about startup and shutdown of the Xwayland
/// instance.
#[derive(Debug)]
            // kill the client
            instance.wayland_client.kill();
            // remove the event source
            if let Some(s) = instance.sigusr1_handler.take() {
                (self.kill_source)(s);
            }
            // All connections and lockfiles are cleaned by their destructors
    type Metadata = ();
    type Ret = ();
    type Error = io::Error;

    fn process_events<F>(
        &mut self,
        readiness: calloop::Readiness,
        token: calloop::Token,
        mut callback: F,
    ) -> io::Result<calloop::PostAction>
    where
        F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
    {
        self.channel
            .process_events(readiness, token, |event, &mut ()| match event {
                channel::Event::Msg(msg) => callback(msg, &mut ()),
                channel::Event::Closed => {}
            })
            .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err))
    }

    fn register(
        &mut self,
        poll: &mut calloop::Poll,
        factory: &mut calloop::TokenFactory,
    ) -> calloop::Result<()> {
        self.channel.register(poll, factory)
    }

    fn reregister(
        &mut self,
        poll: &mut calloop::Poll,
        factory: &mut calloop::TokenFactory,
    ) -> calloop::Result<()> {
        self.channel.reregister(poll, factory)
    }

    fn unregister(&mut self, poll: &mut calloop::Poll) -> calloop::Result<()> {
        self.channel.unregister(poll)
    }
}

impl Inner {
    // Shutdown the XWayland server and cleanup everything
    fn shutdown(&mut self) {
        // don't do anything if not running
        if let Some(instance) = self.instance.take() {
            info!(self.log, "Shutting down XWayland.");
            self.dh
                .backend_handle()
                .kill_client(instance.wayland_client.id(), DisconnectReason::ConnectionClosed);

            // send error occurs if the user dropped the channel... We cannot do much except ignore.
            let _ = self.sender.send(XWaylandEvent::Exited);

            // All connections and lockfiles are cleaned by their destructors

            // Remove DISPLAY from the env
            ::std::env::remove_var("DISPLAY");
            // We do like wlroots:
            // > We do not kill the XWayland process, it dies to broken pipe
            // > after we close our side of the wm/wl fds. This is more reliable
            // > than trying to kill something that might no longer be XWayland.
        }
    }
}

fn xwayland_ready(inner: &Arc<Mutex<Inner>>) {
    // Lots of re-borrowing to please the borrow-checker
    let mut guard = inner.lock().unwrap();
    let guard = &mut *guard;
    info!(guard.log, "XWayland ready");
    // instance should never be None at this point
    let instance = guard.instance.as_mut().unwrap();
    // neither the child_stdout
    let child_stdout = &mut instance.child_stdout;

    }

    // in all cases, cleanup
    if let Some(s) = instance.sigusr1_handler.take() {
        (inner.kill_source)(s);
    }
}
        }
    };

    if success {
        // setup the environment
        ::std::env::set_var("DISPLAY", format!(":{}", instance.display_lock.display()));

        // signal the WM
        info!(
            guard.log,
            "XWayland is ready on DISPLAY \":{}\", signaling the WM.",
            instance.display_lock.display()
        );
        // send error occurs if the user dropped the channel... We cannot do much except ignore.
        let _ = guard.sender.send(XWaylandEvent::Ready {
            connection: instance.wm_fd.take().unwrap(), // This is a bug if None
            client: instance.wayland_client.clone(),
            client_fd: instance.wayland_client_fd,
            display: instance.display_lock.display(),
        });
    } else {
        error!(
            guard.log,
            "XWayland crashed at startup, will not try to restart it."
        );
    }
}

/// Spawn XWayland with given sockets on given display
///
/// Returns a pipe that outputs 'S' upon successful launch.
fn spawn_xwayland(
    display: u32,
    wayland_socket: UnixStream,
    wm_socket: UnixStream,
    listen_sockets: &[UnixStream],
) -> io::Result<ChildStdout> {
    let mut command = Command::new("sh");

    // We use output stream to communicate because FD is easier to handle than exit code.
    command.stdout(Stdio::piped());

    let mut xwayland_args = format!(":{} -rootless -terminate -wm {}", display, wm_socket.as_raw_fd());
    for socket in listen_sockets {
        // Will only fail to write on OOM, so this panic is fine.
        write!(xwayland_args, " -listenfd {}", socket.as_raw_fd()).unwrap();
    }
    // This command let sh to:
    // * Set up signal handler for USR1
    // * Launch Xwayland with USR1 ignored so Xwayland will signal us when it is ready (also redirect
    //   Xwayland's STDOUT to STDERR so its output, if any, won't distract us)
    // * Print "S" and exit if USR1 is received
    command.arg("-c").arg(format!(
        "trap 'echo S' USR1; (trap '' USR1; exec Xwayland {}) 1>&2 & wait",
        xwayland_args
    ));

    // Setup the environment: clear everything except PATH and XDG_RUNTIME_DIR
    command.env_clear();
    for (key, value) in env::vars_os() {
        if key.to_str() == Some("PATH") || key.to_str() == Some("XDG_RUNTIME_DIR") {
            command.env(key, value);
            continue;
        }
    }
    command.env("WAYLAND_SOCKET", format!("{}", wayland_socket.as_raw_fd()));

    unsafe {
        let wayland_socket_fd = wayland_socket.as_raw_fd();
        let wm_socket_fd = wm_socket.as_raw_fd();
        let socket_fds: Vec<_> = listen_sockets.iter().map(|socket| socket.as_raw_fd()).collect();
        command.pre_exec(move || {
            // unset the CLOEXEC flag from the sockets we need to pass
            // to xwayland
            unset_cloexec(wayland_socket_fd)?;
            unset_cloexec(wm_socket_fd)?;
            for &socket in socket_fds.iter() {
                unset_cloexec(socket)?;
            }
            Ok(())
        });
    }

    let mut child = command.spawn()?;
    Ok(child.stdout.take().expect("stdout should be piped"))
}

/// Remove the `O_CLOEXEC` flag from this `Fd`
///
/// This means that the `Fd` will *not* be automatically
/// closed when we `exec()` into XWayland
fn unset_cloexec(fd: RawFd) -> io::Result<()> {
    use nix::fcntl::{fcntl, FcntlArg, FdFlag};
    fcntl(fd, FcntlArg::F_SETFD(FdFlag::empty()))?;
    Ok(())
}

<MSG> xwayland: Use pipe instead of signal

Handling SIGUSR1 requires setting a signal handler, which is a global
resource. This can also cause problems in the presence of threads, since
every thread needs to set up a signal handler. This commit instead
changes the code to use a pipe instead (actually a UnixStream). When the
child closes the pipe, the parent wakes up and knows "to do something".

Fixes: https://github.com/Smithay/smithay/issues/246
Signed-off-by: Uli Schlachter <346c0ad49ac8427b61b3b55abbe37dc0ebd524f2@znc.in>

<DFF> @@ -37,10 +37,7 @@ use std::{
     sync::Arc,
 };
 
-use calloop::{
-    signals::{Signal, Signals},
-    LoopHandle, Source,
-};
+use calloop::{generic::Generic, Interest, LoopHandle, Mode, Source};
 
 use nix::{
     errno::Errno,
@@ -95,13 +92,14 @@ impl<WM: XWindowManager + 'static> XWayland<WM> {
                 let handle = handle.clone();
                 Box::new(move |source| handle.kill(source))
             },
-            source_maker: Box::new(move |inner| {
+            source_maker: Box::new(move |inner, fd| {
                 handle
                     .insert_source(
-                        Signals::new(&[Signal::SIGUSR1]).map_err(|_| ())?,
+                        Generic::new(fd, Interest::Readable, Mode::Level),
                         move |evt, _, _| {
-                            debug_assert!(evt.signal() == Signal::SIGUSR1);
+                            debug_assert!(evt.readable);
                             xwayland_ready(&inner);
+                            Ok(())
                         },
                     )
                     .map_err(|_| ())
@@ -124,13 +122,14 @@ impl<WM: XWindowManager> Drop for XWayland<WM> {
 struct XWaylandInstance {
     display_lock: X11Lock,
     wayland_client: Client,
-    sigusr1_handler: Option<Source<Signals>>,
+    startup_handler: Option<Source<Generic<UnixStream>>>,
     wm_fd: Option<UnixStream>,
     started_at: ::std::time::Instant,
     child_pid: Option<Pid>,
 }
 
-type SourceMaker<WM> = dyn FnMut(Rc<RefCell<Inner<WM>>>) -> Result<Source<Signals>, ()>;
+type SourceMaker<WM> =
+    dyn FnMut(Rc<RefCell<Inner<WM>>>, UnixStream) -> Result<Source<Generic<UnixStream>>, ()>;
 
 // Inner implementation of the XWayland manager
 struct Inner<WM: XWindowManager> {
@@ -138,7 +137,7 @@ struct Inner<WM: XWindowManager> {
     source_maker: Box<SourceMaker<WM>>,
     wayland_display: Rc<RefCell<Display>>,
     instance: Option<XWaylandInstance>,
-    kill_source: Box<dyn Fn(Source<Signals>)>,
+    kill_source: Box<dyn Fn(Source<Generic<UnixStream>>)>,
     log: ::slog::Logger,
 }
 
@@ -156,6 +155,7 @@ fn launch<WM: XWindowManager + 'static, T: Any>(
 
     info!(guard.log, "Starting XWayland");
 
+    let (status_child, status_me) = UnixStream::pair().map_err(|_| ())?;
     let (x_wm_x11, x_wm_me) = UnixStream::pair().map_err(|_| ())?;
     let (wl_x11, wl_me) = UnixStream::pair().map_err(|_| ())?;
 
@@ -178,9 +178,6 @@ fn launch<WM: XWindowManager + 'static, T: Any>(
         client_destroy::<WM, T>(&e, data.get().unwrap())
     }));
 
-    // setup the SIGUSR1 handler
-    let sigusr1_handler = (&mut *guard.source_maker)(inner.clone())?;
-
     // all is ready, we can do the fork dance
     let child_pid = match unsafe { fork() } {
         Ok(ForkResult::Parent { child }) => {
@@ -189,7 +186,6 @@ fn launch<WM: XWindowManager + 'static, T: Any>(
         }
         Ok(ForkResult::Child) => {
             // we are the first child
-            let ppid = Pid::parent();
             let mut set = signal::SigSet::empty();
             set.add(signal::Signal::SIGUSR1);
             set.add(signal::Signal::SIGCHLD);
@@ -197,10 +193,10 @@ fn launch<WM: XWindowManager + 'static, T: Any>(
             let _ = signal::sigprocmask(signal::SigmaskHow::SIG_BLOCK, Some(&set), None);
             match unsafe { fork() } {
                 Ok(ForkResult::Parent { child }) => {
+                    // When we exit(), we will close() this which wakes up the main process.
+                    let _status_child = status_child;
                     // we are still the first child
                     let sig = set.wait();
-                    // send USR1 to parent
-                    let _ = signal::kill(ppid, signal::Signal::SIGUSR1);
                     // Parent will wait for us and know from out
                     // exit status if XWayland launch was a success or not =)
                     if let Ok(signal::Signal::SIGCHLD) = sig {
@@ -234,10 +230,12 @@ fn launch<WM: XWindowManager + 'static, T: Any>(
         }
     };
 
+    let startup_handler = (&mut *guard.source_maker)(inner.clone(), status_me)?;
+
     guard.instance = Some(XWaylandInstance {
         display_lock: lock,
         wayland_client: client,
-        sigusr1_handler: Some(sigusr1_handler),
+        startup_handler: Some(startup_handler),
         wm_fd: Some(x_wm_me),
         started_at: creation_time,
         child_pid: Some(child_pid),
@@ -256,7 +254,7 @@ impl<WM: XWindowManager> Inner<WM> {
             // kill the client
             instance.wayland_client.kill();
             // remove the event source
-            if let Some(s) = instance.sigusr1_handler.take() {
+            if let Some(s) = instance.startup_handler.take() {
                 (self.kill_source)(s);
             }
             // All connections and lockfiles are cleaned by their destructors
@@ -340,7 +338,7 @@ fn xwayland_ready<WM: XWindowManager>(inner: &Rc<RefCell<Inner<WM>>>) {
     }
 
     // in all cases, cleanup
-    if let Some(s) = instance.sigusr1_handler.take() {
+    if let Some(s) = instance.startup_handler.take() {
         (inner.kill_source)(s);
     }
 }

xwayland: Use pipe instead of signal