Skip to content

Commit

Permalink
Re-work egui PID file to fix broken outdated references and not trigg…
Browse files Browse the repository at this point in the history
…ering on deletion (fixes #36)
  • Loading branch information
Alex Saveau committed Oct 26, 2024
1 parent a91365f commit 5132b7c
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 21 deletions.
27 changes: 22 additions & 5 deletions egui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::{
env,
error::Error,
sync::{
Arc, mpsc,
Arc,
atomic::{AtomicBool, Ordering},
mpsc,
mpsc::{Receiver, Sender},
},
thread,
Expand All @@ -31,8 +33,12 @@ use ringboard_sdk::{
controller,
},
};
use rustix::fs::unlink;

use crate::{loader::RingboardLoader, startup::maintain_single_instance};
use crate::{
loader::RingboardLoader,
startup::{maintain_single_instance, sleep_file_name},
};

mod startup;

Expand All @@ -42,7 +48,8 @@ static GLOBAL: tracy_client::ProfiledAllocator<std::alloc::System> =
tracy_client::ProfiledAllocator::new(std::alloc::System, 100);

fn main() -> Result<(), eframe::Error> {
eframe::run_native(
let stop = Arc::new(AtomicBool::new(false));
let result = eframe::run_native(
concat!("Ringboard v", env!("CARGO_PKG_VERSION")),
eframe::NativeOptions {
viewport: ViewportBuilder::default()
Expand Down Expand Up @@ -133,14 +140,15 @@ fn main() -> Result<(), eframe::Error> {

thread::spawn({
let ctx = cc.egui_ctx.clone();
let stop = stop.clone();
move || {
ctx.send_viewport_cmd(ViewportCommand::Icon(Some(
eframe::icon_data::from_png_bytes(include_bytes!("../logo.jpeg"))
.unwrap()
.into(),
)));

if let Err(e) = maintain_single_instance(|| {
if let Err(e) = maintain_single_instance(&stop, || {
ctx.send_viewport_cmd(ViewportCommand::Visible(true));
ctx.send_viewport_cmd(ViewportCommand::Focus);
}) {
Expand All @@ -159,7 +167,16 @@ fn main() -> Result<(), eframe::Error> {
response_receiver,
)))
}),
)
);

stop.store(true, Ordering::Relaxed);
{
let sleep_file = sleep_file_name();
let _ = unlink(&sleep_file)
.inspect_err(|e| eprintln!("Failed to delete sleep file: {sleep_file:?}\nError: {e}"));
}

result
}

struct App {
Expand Down
62 changes: 46 additions & 16 deletions egui/src/startup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,46 @@ use std::{
os::{fd::AsFd, unix::ffi::OsStringExt},
path::PathBuf,
process,
sync::atomic::{AtomicBool, Ordering},
};

use ringboard_sdk::core::{
Error as CoreError, IoErr, dirs::push_sockets_prefix, link_tmp_file, read_lock_file_pid,
};
use rustix::{
fs::{
CWD, Mode, OFlags, inotify,
inotify::{inotify_add_watch, inotify_init},
openat, unlink,
},
io::{Errno, read_uninit},
fs::{CWD, Mode, OFlags, inotify, inotify::ReadFlags, openat, unlink},
io::Errno,
path::Arg,
process::{Signal, getpid, kill_process},
};

pub fn maintain_single_instance(mut open: impl FnMut()) -> Result<(), CoreError> {
pub fn sleep_file_name() -> CString {
let mut path = PathBuf::with_capacity("/tmp/.ringboard/username.egui-sleep".len());
push_sockets_prefix(&mut path);
path.set_extension("egui-sleep");
let path = CString::new(path.into_os_string().into_vec()).unwrap();
CString::new(path.into_os_string().into_vec()).unwrap()
}

pub fn maintain_single_instance(
stop: &AtomicBool,
mut open: impl FnMut(),
) -> Result<(), CoreError> {
let path = sleep_file_name();
let inotify =
inotify_init(inotify::CreateFlags::empty()).map_io_err(|| "Failed to create inotify.")?;
inotify::init(inotify::CreateFlags::empty()).map_io_err(|| "Failed to create inotify.")?;
loop {
if stop.load(Ordering::Relaxed) {
break Ok(());
}

kill_old_instances_if_any(&path)?;
inotify_add_watch(inotify.as_fd(), &path, inotify::WatchFlags::MOVE_SELF)
.map_io_err(|| "Failed to register inotify watch.")?;
wait_for_sleep_cancel(&inotify, &mut open)?;
let id = inotify::add_watch(
&inotify,
&path,
inotify::WatchFlags::MOVE_SELF | inotify::WatchFlags::DELETE_SELF,
)
.map_io_err(|| "Failed to register inotify watch.")?;
wait_for_sleep_cancel(&inotify, id, &mut open)?;
}
}

Expand Down Expand Up @@ -79,10 +90,29 @@ fn kill_old_instances_if_any(path: impl Arg + Copy + Debug) -> Result<(), CoreEr
}
}

fn wait_for_sleep_cancel(inotify: impl AsFd, mut open: impl FnMut()) -> Result<(), CoreError> {
// TODO https://github.com/bytecodealliance/rustix/issues/538#issuecomment-2076539826
let mut buf = [MaybeUninit::uninit(); 32];
read_uninit(inotify, &mut buf).map_io_err(|| "Failed to read inotify event.")?;
fn wait_for_sleep_cancel(
inotify: impl AsFd,
watch_id: i32,
mut open: impl FnMut(),
) -> Result<(), CoreError> {
{
let mut watch_deleted = false;

let mut buf = [MaybeUninit::uninit(); 96];
let mut buf = inotify::Reader::new(&inotify, &mut buf);
loop {
let e = buf.next().map_io_err(|| "Failed to read inotify events")?;
watch_deleted |= e.events().contains(ReadFlags::IGNORED);
if buf.is_buffer_empty() {
break;
}
}

if !watch_deleted {
inotify::remove_watch(&inotify, watch_id)
.map_io_err(|| "Failed to remove inotify watch.")?;
}
}
open();
Ok(())
}

0 comments on commit 5132b7c

Please sign in to comment.