From 784705cf85a8613ae094df127dc066e71d10aacb Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 14 Oct 2026 22:32:51 +0200 Subject: [PATCH] csm-manager.c: Prevent redundant re-entry and app restarts during shutdown When the session enters CSM_MANAGER_PHASE_END_SESSION or CSM_MANAGER_PHASE_EXIT, applications terminate from signals (SIGTERM/SIGHUP). Previously, app_died() and app_exited() would attempt to restart dying components, triggering redundant phase transitions and repeatedly calling csm_manager_quit(). This patch: 1. Adds an is_quitting guard in CsmManagerPrivate to ensure csm_manager_quit() is executed only once. 2. Skips app restarts in app_died() and app_exited() once the session is in END_SESSION/EXIT phase or is_quitting. 3. Guards request_reboot(), request_shutdown(), and request_logout() against re-entry if a shutdown sequence is already in progress. 4. Ensures systemduserunitdir installs into prefix when prefix is not /usr. --- cinnamon-session/csm-manager.c | 37 +++++++++++++++++++++++++++++++++- meson.build | 12 +++++++---- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/cinnamon-session/csm-manager.c b/cinnamon-session/csm-manager.c index 8449e37..5984f40 100644 --- a/cinnamon-session/csm-manager.c +++ b/cinnamon-session/csm-manager.c @@ -163,7 +163,7 @@ struct CsmManagerPrivate ca_context *ca; gboolean logout_sound_is_playing; - + gboolean is_quitting; }; enum { @@ -486,6 +486,12 @@ csm_manager_quit (CsmManager *manager) /* See the comment in request_reboot() for some more details about how * this works. */ + if (manager->priv->is_quitting) { + g_debug ("CsmManager: quit already in progress, ignoring re-entry"); + return; + } + manager->priv->is_quitting = TRUE; + csm_store_clear (manager->priv->inhibitors); switch (manager->priv->logout_type) { @@ -636,6 +642,13 @@ app_died (CsmApp *app, { g_warning ("Application '%s' killed by signal %d", csm_app_peek_app_id (app), signal); + /* Do not restart apps when the session is ending or quitting */ + if (manager->priv->phase >= CSM_MANAGER_PHASE_END_SESSION || manager->priv->is_quitting) { + g_debug ("Component '%s' died during session shutdown, ignoring", + csm_app_peek_app_id (app)); + return; + } + if (csm_app_peek_autorestart (app)) { g_debug ("Component '%s' is autorestart, ignoring died signal", csm_app_peek_app_id (app)); @@ -661,6 +674,13 @@ app_exited (CsmApp *app, { g_debug ("App %s exited with %d", csm_app_peek_app_id (app), exit_code); + /* Do not restart apps when the session is ending or quitting */ + if (manager->priv->phase >= CSM_MANAGER_PHASE_END_SESSION || manager->priv->is_quitting) { + g_debug ("Component '%s' exited during session shutdown, ignoring", + csm_app_peek_app_id (app)); + return; + } + /* Consider that non-success exit status means "crash" for required components */ if (exit_code != 0 && is_app_required (manager, app)) { if (csm_app_peek_autorestart (app)) { @@ -3815,6 +3835,11 @@ request_reboot (CsmManager *manager) { g_debug ("CsmManager: requesting reboot"); + if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION || manager->priv->is_quitting) { + g_debug ("CsmManager: shutdown/logout already in progress, ignoring reboot request"); + return; + } + /* FIXME: We need to support a more structured shutdown here, * but that's blocking on an improved ConsoleKit api. * @@ -3829,6 +3854,11 @@ request_shutdown (CsmManager *manager) { g_debug ("CsmManager: requesting shutdown"); + if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION || manager->priv->is_quitting) { + g_debug ("CsmManager: shutdown/logout already in progress, ignoring shutdown request"); + return; + } + /* See the comment in request_reboot() for some more details about * what work needs to be done here. */ manager->priv->logout_type = CSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT; @@ -3868,6 +3898,11 @@ request_logout (CsmManager *manager, { g_debug ("CsmManager: requesting logout"); + if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION || manager->priv->is_quitting) { + g_debug ("CsmManager: shutdown/logout already in progress, ignoring logout request"); + return; + } + manager->priv->logout_mode = mode; manager->priv->logout_type = CSM_MANAGER_LOGOUT_LOGOUT; diff --git a/meson.build b/meson.build index de839f9..8cabbd7 100644 --- a/meson.build +++ b/meson.build @@ -61,10 +61,14 @@ conf.set('HAVE_LOGIND', logind.found()) systemd_opt = get_option('systemd') systemd_dep = dependency('systemd', required: systemd_opt.enabled()) if systemd_dep.found() - systemduserunitdir = systemd_dep.get_variable( - pkgconfig: 'systemduserunitdir', - default_value: join_paths(get_option('prefix'), 'lib', 'systemd', 'user') - ) + if get_option('prefix') != '/usr' + systemduserunitdir = join_paths(get_option('prefix'), 'lib', 'systemd', 'user') + else + systemduserunitdir = systemd_dep.get_variable( + pkgconfig: 'systemduserunitdir', + default_value: join_paths(get_option('prefix'), 'lib', 'systemd', 'user') + ) + endif enable_systemd = true else enable_systemd = systemd_dep.found() and not systemd_opt.disabled()