fix(session): relancer cosmic-settings-daemon s'il sort proprement en session
launch-pad ne relance que les processus qui sortent en erreur: une sortie propre du demon (par ex. un pkill -x cosmic-settings qui touche aussi le demon a cause de la troncature comm a 15 caracteres) laissait la session sans service varlink audio jusqu'au logout. Le demon est desormais relance par cosmic-session tant que la session n'est pas en cours d'extinction, avec une limite de 5 relances rapprochées pour éviter une boucle sur un démon cassé.
This commit is contained in:
parent
d97b142f35
commit
bc61bfddcc
2 changed files with 130 additions and 41 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
|
@ -299,7 +299,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-session"
|
name = "cosmic-session"
|
||||||
version = "1.0.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"cosmic-dbus-a11y",
|
"cosmic-dbus-a11y",
|
||||||
|
|
@ -1885,6 +1885,18 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[patch.unused]]
|
||||||
|
name = "softbuffer"
|
||||||
|
version = "0.4.1"
|
||||||
|
|
||||||
|
[[patch.unused]]
|
||||||
|
name = "cosmic-freedesktop-icons"
|
||||||
|
version = "0.4.0"
|
||||||
|
|
||||||
|
[[patch.unused]]
|
||||||
|
name = "smithay-clipboard"
|
||||||
|
version = "0.8.0"
|
||||||
|
|
||||||
[[patch.unused]]
|
[[patch.unused]]
|
||||||
name = "dpi"
|
name = "dpi"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
@ -1932,15 +1944,3 @@ version = "0.31.0-beta.2"
|
||||||
[[patch.unused]]
|
[[patch.unused]]
|
||||||
name = "winit-x11"
|
name = "winit-x11"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
|
||||||
[[patch.unused]]
|
|
||||||
name = "smithay-clipboard"
|
|
||||||
version = "0.8.0"
|
|
||||||
|
|
||||||
[[patch.unused]]
|
|
||||||
name = "cosmic-freedesktop-icons"
|
|
||||||
version = "0.4.0"
|
|
||||||
|
|
||||||
[[patch.unused]]
|
|
||||||
name = "softbuffer"
|
|
||||||
version = "0.4.1"
|
|
||||||
|
|
|
||||||
145
src/main.rs
145
src/main.rs
|
|
@ -221,38 +221,24 @@ async fn start(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let stdout_span = info_span!(parent: None, "cosmic-settings-daemon");
|
|
||||||
let stderr_span = stdout_span.clone();
|
|
||||||
let (settings_exit_tx, settings_exit_rx) = oneshot::channel();
|
let (settings_exit_tx, settings_exit_rx) = oneshot::channel();
|
||||||
let settings_exit_tx = Arc::new(std::sync::Mutex::new(Some(settings_exit_tx)));
|
let settings_exit_tx = Arc::new(std::sync::Mutex::new(Some(settings_exit_tx)));
|
||||||
|
let shutting_down = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||||
|
let settings_daemon_key = Arc::new(std::sync::Mutex::new(None));
|
||||||
|
let respawn_count = Arc::new(std::sync::atomic::AtomicUsize::new(0));
|
||||||
|
let last_respawn = Arc::new(std::sync::Mutex::new(std::time::Instant::now()));
|
||||||
let settings_daemon = process_manager
|
let settings_daemon = process_manager
|
||||||
.start(
|
.start(settings_daemon_process(
|
||||||
Process::new()
|
env_vars.clone(),
|
||||||
.with_executable("cosmic-settings-daemon")
|
Arc::clone(&shutting_down),
|
||||||
.with_env(env_vars.iter().cloned())
|
Arc::clone(&settings_exit_tx),
|
||||||
.with_on_stdout(move |_, _, line| {
|
Arc::clone(&settings_daemon_key),
|
||||||
let stdout_span = stdout_span.clone();
|
Arc::clone(&respawn_count),
|
||||||
async move {
|
Arc::clone(&last_respawn),
|
||||||
info!("{}", line);
|
))
|
||||||
}
|
|
||||||
.instrument(stdout_span)
|
|
||||||
})
|
|
||||||
.with_on_stderr(move |_, _, line| {
|
|
||||||
let stderr_span = stderr_span.clone();
|
|
||||||
async move {
|
|
||||||
warn!("{}", line);
|
|
||||||
}
|
|
||||||
.instrument(stderr_span)
|
|
||||||
})
|
|
||||||
.with_on_exit(move |_, _, _, will_restart| {
|
|
||||||
if !will_restart && let Some(tx) = settings_exit_tx.lock().unwrap().take() {
|
|
||||||
_ = tx.send(());
|
|
||||||
}
|
|
||||||
async {}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.expect("failed to start settings daemon");
|
.expect("failed to start settings daemon");
|
||||||
|
*settings_daemon_key.lock().unwrap() = Some(settings_daemon);
|
||||||
|
|
||||||
// notifying the user service manager that we've reached the
|
// notifying the user service manager that we've reached the
|
||||||
// graphical-session.target, which should only happen after:
|
// graphical-session.target, which should only happen after:
|
||||||
|
|
@ -487,7 +473,13 @@ async fn start(
|
||||||
|
|
||||||
compositor_handle.abort();
|
compositor_handle.abort();
|
||||||
token.cancel();
|
token.cancel();
|
||||||
if let Err(err) = process_manager.stop_process(settings_daemon).await {
|
shutting_down.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
let settings_daemon_stop = settings_daemon_key
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.take()
|
||||||
|
.unwrap_or(settings_daemon);
|
||||||
|
if let Err(err) = process_manager.stop_process(settings_daemon_stop).await {
|
||||||
tracing::error!(?err, "Failed to gracefully stop settings daemon.");
|
tracing::error!(?err, "Failed to gracefully stop settings daemon.");
|
||||||
} else {
|
} else {
|
||||||
match tokio::time::timeout(Duration::from_secs(1), settings_exit_rx).await {
|
match tokio::time::timeout(Duration::from_secs(1), settings_exit_rx).await {
|
||||||
|
|
@ -502,6 +494,103 @@ async fn start(
|
||||||
Ok(status)
|
Ok(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build the cosmic-settings-daemon process.
|
||||||
|
///
|
||||||
|
/// The daemon is respawned whenever it exits while the session is still
|
||||||
|
/// running: launch-pad only restarts processes that exit with an error, so a
|
||||||
|
/// clean exit (for example a stray `pkill` matching the daemon's truncated
|
||||||
|
/// comm name) would otherwise leave the session without the varlink audio
|
||||||
|
/// service until logout. Rapid successive exits are capped to avoid a respawn
|
||||||
|
/// loop of a daemon that cannot stay alive.
|
||||||
|
fn settings_daemon_process(
|
||||||
|
env_vars: Vec<(String, String)>,
|
||||||
|
shutting_down: Arc<std::sync::atomic::AtomicBool>,
|
||||||
|
settings_exit_tx: Arc<std::sync::Mutex<Option<oneshot::Sender<()>>>>,
|
||||||
|
settings_daemon_key: Arc<std::sync::Mutex<Option<launch_pad::ProcessKey>>>,
|
||||||
|
respawn_count: Arc<std::sync::atomic::AtomicUsize>,
|
||||||
|
last_respawn: Arc<std::sync::Mutex<std::time::Instant>>,
|
||||||
|
) -> Process {
|
||||||
|
let stdout_span = info_span!(parent: None, "cosmic-settings-daemon");
|
||||||
|
let stderr_span = stdout_span.clone();
|
||||||
|
let respawn_env = env_vars.clone();
|
||||||
|
|
||||||
|
Process::new()
|
||||||
|
.with_executable("cosmic-settings-daemon")
|
||||||
|
.with_env(env_vars.iter().cloned())
|
||||||
|
.with_on_stdout(move |_, _, line| {
|
||||||
|
let stdout_span = stdout_span.clone();
|
||||||
|
async move {
|
||||||
|
info!("{}", line);
|
||||||
|
}
|
||||||
|
.instrument(stdout_span)
|
||||||
|
})
|
||||||
|
.with_on_stderr(move |_, _, line| {
|
||||||
|
let stderr_span = stderr_span.clone();
|
||||||
|
async move {
|
||||||
|
warn!("{}", line);
|
||||||
|
}
|
||||||
|
.instrument(stderr_span)
|
||||||
|
})
|
||||||
|
.with_on_exit(move |pman, _key, _err_code, will_restart| {
|
||||||
|
let shutting_down = Arc::clone(&shutting_down);
|
||||||
|
let settings_exit_tx = Arc::clone(&settings_exit_tx);
|
||||||
|
let settings_daemon_key = Arc::clone(&settings_daemon_key);
|
||||||
|
let respawn_count = Arc::clone(&respawn_count);
|
||||||
|
let last_respawn = Arc::clone(&last_respawn);
|
||||||
|
let respawn_env = respawn_env.clone();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
if will_restart {
|
||||||
|
// launch-pad restarts processes that exit with an error on its own.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if shutting_down.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
|
if let Some(tx) = settings_exit_tx.lock().unwrap().take() {
|
||||||
|
_ = tx.send(());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = std::time::Instant::now();
|
||||||
|
{
|
||||||
|
let mut last = last_respawn.lock().unwrap();
|
||||||
|
if now.duration_since(*last) > Duration::from_secs(60) {
|
||||||
|
respawn_count.store(0, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
*last = now;
|
||||||
|
}
|
||||||
|
let count =
|
||||||
|
respawn_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
|
||||||
|
if count > 5 {
|
||||||
|
error!(
|
||||||
|
"cosmic-settings-daemon exited {count} times in quick succession; giving up on respawns"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("cosmic-settings-daemon exited unexpectedly; respawning it");
|
||||||
|
let new_process = settings_daemon_process(
|
||||||
|
respawn_env,
|
||||||
|
shutting_down.clone(),
|
||||||
|
settings_exit_tx.clone(),
|
||||||
|
settings_daemon_key.clone(),
|
||||||
|
respawn_count.clone(),
|
||||||
|
last_respawn.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
match pman.start(new_process).await {
|
||||||
|
Ok(new_key) => {
|
||||||
|
*settings_daemon_key.lock().unwrap() = Some(new_key);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!(?err, "Failed to respawn cosmic-settings-daemon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fn start_component(
|
async fn start_component(
|
||||||
cmd: impl Into<Cow<'static, str>>,
|
cmd: impl Into<Cow<'static, str>>,
|
||||||
span: tracing::Span,
|
span: tracing::Span,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue