fix: wayland lockfile

This commit is contained in:
Nova
2025-07-13 21:26:56 -07:00
parent 58328cd63b
commit d360a57f6e
4 changed files with 20 additions and 20 deletions

2
Cargo.lock generated
View File

@@ -5374,12 +5374,10 @@ dependencies = [
"global_counter", "global_counter",
"input-event-codes", "input-event-codes",
"lazy_static", "lazy_static",
"libc",
"memfd", "memfd",
"memmap2", "memmap2",
"mint", "mint",
"nanoid", "nanoid",
"nix 0.30.1",
"openxr", "openxr",
"parking_lot 0.12.4", "parking_lot 0.12.4",
"rand", "rand",

View File

@@ -139,8 +139,6 @@ tokio-stream = { version = "0.1.17", optional = true }
memmap2 = { version = "0.9.5", optional = true } memmap2 = { version = "0.9.5", optional = true }
drm-fourcc = { version = "2.2.0", optional = true } drm-fourcc = { version = "2.2.0", optional = true }
memfd = { version = "0.6.4", optional = true } memfd = { version = "0.6.4", optional = true }
libc = "0.2.172"
nix = "0.30.1"
[dependencies.stardust-xr] [dependencies.stardust-xr]
workspace = true workspace = true

View File

@@ -190,7 +190,7 @@ async fn main() -> Result<AppExit, JoinError> {
"Couldn't make the object registry to find all objects with given interfaces in d-bus", "Couldn't make the object registry to find all objects with given interfaces in d-bus",
); );
let _wayland = Wayland::new(None).expect("Couldn't create Wayland instance"); let _wayland = Wayland::new().expect("Couldn't create Wayland instance");
let ready_notifier = Arc::new(Notify::new()); let ready_notifier = Arc::new(Notify::new());
let io_loop = tokio::task::spawn_blocking({ let io_loop = tokio::task::spawn_blocking({

View File

@@ -19,7 +19,7 @@ use bevy::render::renderer::RenderDevice;
use bevy::render::{Render, RenderApp}; use bevy::render::{Render, RenderApp};
use bevy::{asset::Assets, ecs::resource::Resource, image::Image}; use bevy::{asset::Assets, ecs::resource::Resource, image::Image};
use bevy_dmabuf::import::ImportedDmatexs; use bevy_dmabuf::import::ImportedDmatexs;
use cluFlock::ToFlock; use cluFlock::{FlockLock, ToFlock};
use core::{ use core::{
buffer::{Buffer, WL_BUFFER_REGISTRY}, buffer::{Buffer, WL_BUFFER_REGISTRY},
callback::Callback, callback::Callback,
@@ -27,6 +27,7 @@ use core::{
surface::WL_SURFACE_REGISTRY, surface::WL_SURFACE_REGISTRY,
}; };
use mint::Vector2; use mint::Vector2;
use std::fs::File;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::{ use std::{
fs::{self, OpenOptions}, fs::{self, OpenOptions},
@@ -58,7 +59,7 @@ impl From<waynest::server::Error> for ServerError {
} }
} }
pub fn get_free_wayland_socket_path() -> Option<PathBuf> { pub fn get_free_wayland_socket_path() -> Option<(PathBuf, FlockLock<File>)> {
// Use XDG runtime directory for secure, user-specific sockets // Use XDG runtime directory for secure, user-specific sockets
let base_dirs = directories::BaseDirs::new()?; let base_dirs = directories::BaseDirs::new()?;
let runtime_dir = base_dirs.runtime_dir()?; let runtime_dir = base_dirs.runtime_dir()?;
@@ -69,19 +70,21 @@ pub fn get_free_wayland_socket_path() -> Option<PathBuf> {
let socket_lock_path = runtime_dir.join(format!("wayland-{display}.lock")); let socket_lock_path = runtime_dir.join(format!("wayland-{display}.lock"));
// Open lock file without truncation to preserve existing locks // Open lock file without truncation to preserve existing locks
let mut _lock = OpenOptions::new() let Ok(lock) = OpenOptions::new()
.create(true) .create(true)
.truncate(false) // Prevent destroying other processes' locks .truncate(false) // Prevent destroying other processes' locks
.read(true) .read(true)
.write(true) .write(true)
.mode(0o660) // Match Wayland-compositor permissions .mode(0o660) // Match Wayland-compositor permissions
.open(&socket_lock_path) .open(&socket_lock_path)
.ok()?; else {
continue;
};
// Atomic mutual exclusion: fail if another process holds the lock // Atomic mutual exclusion: fail if another process holds the lock\
if _lock.try_exclusive_lock().is_err() { let Ok(lock) = lock.try_exclusive_lock() else {
continue; // Lock held by active compositor continue; // Lock held by active compositor
} };
// Check for zombie sockets (file exists but nothing listening) // Check for zombie sockets (file exists but nothing listening)
if socket_path.exists() { if socket_path.exists() {
@@ -96,7 +99,7 @@ pub fn get_free_wayland_socket_path() -> Option<PathBuf> {
} }
// Found viable candidate: lock held, socket cleared/available // Found viable candidate: lock held, socket cleared/available
return Some(socket_path); return Some((socket_path, lock));
} }
None // Exhausted all conventional display numbers None // Exhausted all conventional display numbers
@@ -233,17 +236,15 @@ impl Drop for WaylandClient {
#[derive(Debug, Resource)] #[derive(Debug, Resource)]
pub struct Wayland { pub struct Wayland {
lockfile: FlockLock<File>,
abort_handle: AbortHandle, abort_handle: AbortHandle,
} }
impl Wayland { impl Wayland {
pub fn new(socket_path: Option<PathBuf>) -> Result<Self> { pub fn new() -> Result<Self> {
let socket_path = if let Some(path) = socket_path { let (socket_path, lockfile) =
path
} else {
get_free_wayland_socket_path().ok_or(ServerError::WaylandError( get_free_wayland_socket_path().ok_or(ServerError::WaylandError(
waynest::server::Error::IoError(std::io::ErrorKind::AddrNotAvailable.into()), waynest::server::Error::IoError(std::io::ErrorKind::AddrNotAvailable.into()),
))? ))?;
};
let _ = WAYLAND_DISPLAY.set(socket_path.clone()); let _ = WAYLAND_DISPLAY.set(socket_path.clone());
@@ -253,7 +254,10 @@ impl Wayland {
let abort_handle = let abort_handle =
task::new(|| "wayland loop", Self::handle_wayland_loop(listener))?.abort_handle(); task::new(|| "wayland loop", Self::handle_wayland_loop(listener))?.abort_handle();
Ok(Self { abort_handle }) Ok(Self {
lockfile,
abort_handle,
})
} }
async fn handle_wayland_loop(mut listener: server::Listener) -> Result<()> { async fn handle_wayland_loop(mut listener: server::Listener) -> Result<()> {
let mut clients = Vec::new(); let mut clients = Vec::new();