plymouth/SOURCES/0001-device-manager-don-t-w...

490 lines
20 KiB
Diff

From b5bacf2b5e5d9e58cbe96fda0a56baf5dfa11358 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 10 Oct 2018 20:07:37 +0100
Subject: [PATCH] device-manager: don't watch for udev events when deactivated
If a device gets added when we're already deactivated, plymouth shouldn't
process the device, since processing it effectively activates plymouth.
This commit pulls the udev monitor fd out of the event loop while
plymouth is deactivated so new events are deferred until reactivation.
Modified by Iain Lane <iain.lane@canonical.com>: Also deactivate the
timer that finds all devices known to udev after an interval, when
paused.
---
src/libply-splash-core/ply-device-manager.c | 74 +++++++++++++++++----
src/libply-splash-core/ply-device-manager.h | 2 +
src/main.c | 3 +
3 files changed, 67 insertions(+), 12 deletions(-)
diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c
index b637fb8..82f0137 100644
--- a/src/libply-splash-core/ply-device-manager.c
+++ b/src/libply-splash-core/ply-device-manager.c
@@ -36,74 +36,78 @@
#include "ply-logger.h"
#include "ply-event-loop.h"
#include "ply-hashtable.h"
#include "ply-list.h"
#include "ply-utils.h"
#define SUBSYSTEM_DRM "drm"
#define SUBSYSTEM_FRAME_BUFFER "graphics"
#ifdef HAVE_UDEV
static void create_devices_from_udev (ply_device_manager_t *manager);
#endif
static bool create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
const char *device_path,
ply_terminal_t *terminal,
ply_renderer_type_t renderer_type);
struct _ply_device_manager
{
ply_device_manager_flags_t flags;
ply_event_loop_t *loop;
ply_hashtable_t *terminals;
ply_hashtable_t *renderers;
ply_terminal_t *local_console_terminal;
ply_list_t *keyboards;
ply_list_t *text_displays;
ply_list_t *pixel_displays;
struct udev *udev_context;
struct udev_monitor *udev_monitor;
+ ply_fd_watch_t *fd_watch;
ply_keyboard_added_handler_t keyboard_added_handler;
ply_keyboard_removed_handler_t keyboard_removed_handler;
ply_pixel_display_added_handler_t pixel_display_added_handler;
ply_pixel_display_removed_handler_t pixel_display_removed_handler;
ply_text_display_added_handler_t text_display_added_handler;
ply_text_display_removed_handler_t text_display_removed_handler;
void *event_handler_data;
uint32_t local_console_managed : 1;
uint32_t local_console_is_text : 1;
uint32_t serial_consoles_detected : 1;
uint32_t renderers_activated : 1;
uint32_t keyboards_activated : 1;
+
+ uint32_t paused : 1;
+ uint32_t device_timeout_elapsed : 1;
};
static void
detach_from_event_loop (ply_device_manager_t *manager)
{
assert (manager != NULL);
manager->loop = NULL;
}
static void
attach_to_event_loop (ply_device_manager_t *manager,
ply_event_loop_t *loop)
{
assert (manager != NULL);
assert (loop != NULL);
assert (manager->loop == NULL);
manager->loop = loop;
ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
detach_from_event_loop,
manager);
}
static void
free_displays_for_renderer (ply_device_manager_t *manager,
ply_renderer_t *renderer)
{
ply_list_node_t *node;
@@ -348,77 +352,92 @@ on_udev_event (ply_device_manager_t *manager)
return;
if (strcmp (action, "add") == 0) {
const char *subsystem;
subsystem = udev_device_get_subsystem (device);
if (strcmp (subsystem, SUBSYSTEM_DRM) == 0) {
if (manager->local_console_managed && manager->local_console_is_text)
ply_trace ("ignoring since we're already using text splash for local console");
else
create_devices_for_udev_device (manager, device);
} else {
ply_trace ("ignoring since we only handle subsystem %s devices after timeout", subsystem);
}
} else if (strcmp (action, "remove") == 0) {
free_devices_for_udev_device (manager, device);
}
udev_device_unref (device);
}
static void
watch_for_udev_events (ply_device_manager_t *manager)
{
int fd;
assert (manager != NULL);
assert (manager->udev_monitor == NULL);
+ if (manager->fd_watch != NULL)
+ return;
+
ply_trace ("watching for udev graphics device add and remove events");
- manager->udev_monitor = udev_monitor_new_from_netlink (manager->udev_context, "udev");
+ if (manager->udev_monitor == NULL) {
+ manager->udev_monitor = udev_monitor_new_from_netlink (manager->udev_context, "udev");
- udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_DRM, NULL);
- udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_FRAME_BUFFER, NULL);
- udev_monitor_filter_add_match_tag (manager->udev_monitor, "seat");
- udev_monitor_enable_receiving (manager->udev_monitor);
+ udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_DRM, NULL);
+ udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_FRAME_BUFFER, NULL);
+ udev_monitor_filter_add_match_tag (manager->udev_monitor, "seat");
+ udev_monitor_enable_receiving (manager->udev_monitor);
+ }
fd = udev_monitor_get_fd (manager->udev_monitor);
- ply_event_loop_watch_fd (manager->loop,
- fd,
- PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
- (ply_event_handler_t)
- on_udev_event,
- NULL,
- manager);
+ manager->fd_watch = ply_event_loop_watch_fd (manager->loop,
+ fd,
+ PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
+ (ply_event_handler_t)
+ on_udev_event,
+ NULL,
+ manager);
+}
+
+static void
+stop_watching_for_udev_events (ply_device_manager_t *manager)
+{
+ if (manager->fd_watch == NULL)
+ return;
+
+ ply_event_loop_stop_watching_fd (manager->loop, manager->fd_watch);
+ manager->fd_watch = NULL;
}
#endif
static void
free_terminal (char *device,
ply_terminal_t *terminal,
ply_device_manager_t *manager)
{
ply_hashtable_remove (manager->terminals, device);
ply_terminal_free (terminal);
}
static void
free_terminals (ply_device_manager_t *manager)
{
ply_hashtable_foreach (manager->terminals,
(ply_hashtable_foreach_func_t *)
free_terminal,
manager);
}
static ply_terminal_t *
get_terminal (ply_device_manager_t *manager,
const char *device_name)
{
char *full_name = NULL;
ply_terminal_t *terminal;
if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0)
@@ -774,60 +793,67 @@ create_devices_from_terminals (ply_device_manager_t *manager)
if (has_serial_consoles) {
ply_trace ("serial consoles detected, managing them with details forced");
manager->serial_consoles_detected = true;
ply_hashtable_foreach (manager->terminals,
(ply_hashtable_foreach_func_t *)
create_devices_for_terminal,
manager);
return true;
}
return false;
}
static void
create_non_graphical_devices (ply_device_manager_t *manager)
{
create_devices_for_terminal_and_renderer_type (manager,
NULL,
manager->local_console_terminal,
PLY_RENDERER_TYPE_NONE);
}
#ifdef HAVE_UDEV
static void
create_devices_from_udev (ply_device_manager_t *manager)
{
bool found_drm_device, found_fb_device;
+ manager->device_timeout_elapsed = true;
+
+ if (manager->paused) {
+ ply_trace ("create_devices_from_udev timeout elapsed while paused, deferring execution");
+ return;
+ }
+
ply_trace ("Timeout elapsed, looking for devices from udev");
found_drm_device = create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
found_fb_device = create_devices_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
if (found_drm_device || found_fb_device)
return;
ply_trace ("Creating non-graphical devices, since there's no suitable graphics hardware");
create_non_graphical_devices (manager);
}
#endif
static void
create_fallback_devices (ply_device_manager_t *manager)
{
create_devices_for_terminal_and_renderer_type (manager,
NULL,
manager->local_console_terminal,
PLY_RENDERER_TYPE_AUTO);
}
void
ply_device_manager_watch_devices (ply_device_manager_t *manager,
double device_timeout,
ply_keyboard_added_handler_t keyboard_added_handler,
ply_keyboard_removed_handler_t keyboard_removed_handler,
ply_pixel_display_added_handler_t pixel_display_added_handler,
ply_pixel_display_removed_handler_t pixel_display_removed_handler,
ply_text_display_added_handler_t text_display_added_handler,
@@ -965,30 +991,54 @@ ply_device_manager_activate_keyboards (ply_device_manager_t *manager)
ply_keyboard_watch_for_input (keyboard);
node = next_node;
}
manager->keyboards_activated = true;
}
void
ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager)
{
ply_list_node_t *node;
ply_trace ("deactivating keyboards");
node = ply_list_get_first_node (manager->keyboards);
while (node != NULL) {
ply_keyboard_t *keyboard;
ply_list_node_t *next_node;
keyboard = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (manager->keyboards, node);
ply_keyboard_stop_watching_for_input (keyboard);
node = next_node;
}
manager->keyboards_activated = false;
}
+
+void
+ply_device_manager_pause (ply_device_manager_t *manager)
+{
+ ply_trace ("ply_device_manager_pause() called, stopping watching for udev events");
+ manager->paused = true;
+#ifdef HAVE_UDEV
+ stop_watching_for_udev_events (manager);
+#endif
+}
+
+void
+ply_device_manager_unpause (ply_device_manager_t *manager)
+{
+ ply_trace ("ply_device_manager_unpause() called, resuming watching for udev events");
+ manager->paused = false;
+#ifdef HAVE_UDEV
+ if (manager->device_timeout_elapsed) {
+ ply_trace ("ply_device_manager_unpause(): timeout elapsed while paused, looking for udev devices");
+ create_devices_from_udev (manager);
+ }
+ watch_for_udev_events (manager);
+#endif
+}
diff --git a/src/libply-splash-core/ply-device-manager.h b/src/libply-splash-core/ply-device-manager.h
index ad05897..389b636 100644
--- a/src/libply-splash-core/ply-device-manager.h
+++ b/src/libply-splash-core/ply-device-manager.h
@@ -28,46 +28,48 @@
#include "ply-text-display.h"
typedef enum
{
PLY_DEVICE_MANAGER_FLAGS_NONE = 0,
PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES = 1 << 0,
PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV = 1 << 1,
PLY_DEVICE_MANAGER_FLAGS_SKIP_RENDERERS = 1 << 2
} ply_device_manager_flags_t;
typedef struct _ply_device_manager ply_device_manager_t;
typedef void (* ply_keyboard_added_handler_t) (void *, ply_keyboard_t *);
typedef void (* ply_keyboard_removed_handler_t) (void *, ply_keyboard_t *);
typedef void (* ply_pixel_display_added_handler_t) (void *, ply_pixel_display_t *);
typedef void (* ply_pixel_display_removed_handler_t) (void *, ply_pixel_display_t *);
typedef void (* ply_text_display_added_handler_t) (void *, ply_text_display_t *);
typedef void (* ply_text_display_removed_handler_t) (void *, ply_text_display_t *);
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
ply_device_manager_t *ply_device_manager_new (const char *default_tty,
ply_device_manager_flags_t flags);
void ply_device_manager_watch_devices (ply_device_manager_t *manager,
double device_timeout,
ply_keyboard_added_handler_t keyboard_added_handler,
ply_keyboard_removed_handler_t keyboard_removed_handler,
ply_pixel_display_added_handler_t pixel_display_added_handler,
ply_pixel_display_removed_handler_t pixel_display_removed_handler,
ply_text_display_added_handler_t text_display_added_handler,
ply_text_display_removed_handler_t text_display_removed_handler,
void *data);
+void ply_device_manager_pause (ply_device_manager_t *manager);
+void ply_device_manager_unpause (ply_device_manager_t *manager);
bool ply_device_manager_has_serial_consoles (ply_device_manager_t *manager);
bool ply_device_manager_has_displays (ply_device_manager_t *manager);
ply_list_t *ply_device_manager_get_keyboards (ply_device_manager_t *manager);
ply_list_t *ply_device_manager_get_pixel_displays (ply_device_manager_t *manager);
ply_list_t *ply_device_manager_get_text_displays (ply_device_manager_t *manager);
void ply_device_manager_free (ply_device_manager_t *manager);
void ply_device_manager_activate_keyboards (ply_device_manager_t *manager);
void ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager);
void ply_device_manager_activate_renderers (ply_device_manager_t *manager);
void ply_device_manager_deactivate_renderers (ply_device_manager_t *manager);
ply_terminal_t *ply_device_manager_get_default_terminal (ply_device_manager_t *manager);
#endif
#endif
/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/main.c b/src/main.c
index e44de7b..3253aa9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1305,94 +1305,97 @@ on_boot_splash_idle (state_t *state)
ply_trace ("quitting program");
quit_program (state);
} else if (state->deactivate_trigger != NULL) {
ply_trace ("deactivating splash");
deactivate_splash (state);
}
}
static void
on_deactivate (state_t *state,
ply_trigger_t *deactivate_trigger)
{
if (state->is_inactive) {
ply_trigger_pull (deactivate_trigger, NULL);
return;
}
if (state->deactivate_trigger != NULL) {
ply_trigger_add_handler (state->deactivate_trigger,
(ply_trigger_handler_t)
ply_trigger_pull,
deactivate_trigger);
return;
}
state->deactivate_trigger = deactivate_trigger;
ply_trace ("deactivating");
cancel_pending_delayed_show (state);
+ ply_device_manager_pause (state->device_manager);
ply_device_manager_deactivate_keyboards (state->device_manager);
if (state->boot_splash != NULL) {
ply_boot_splash_become_idle (state->boot_splash,
(ply_boot_splash_on_idle_handler_t)
on_boot_splash_idle,
state);
} else {
ply_trace ("deactivating splash");
deactivate_splash (state);
}
}
static void
on_reactivate (state_t *state)
{
if (!state->is_inactive)
return;
if (state->local_console_terminal != NULL) {
ply_terminal_open (state->local_console_terminal);
ply_terminal_watch_for_vt_changes (state->local_console_terminal);
ply_terminal_set_unbuffered_input (state->local_console_terminal);
ply_terminal_ignore_mode_changes (state->local_console_terminal, false);
}
if ((state->session != NULL) && state->should_be_attached) {
ply_trace ("reactivating terminal session");
attach_to_running_session (state);
}
ply_device_manager_activate_keyboards (state->device_manager);
ply_device_manager_activate_renderers (state->device_manager);
+ ply_device_manager_unpause (state->device_manager);
+
state->is_inactive = false;
update_display (state);
}
static void
on_quit (state_t *state,
bool retain_splash,
ply_trigger_t *quit_trigger)
{
ply_trace ("quitting (retain splash: %s)", retain_splash ? "true" : "false");
if (state->quit_trigger != NULL) {
ply_trace ("quit trigger already pending, so chaining to it");
ply_trigger_add_handler (state->quit_trigger,
(ply_trigger_handler_t)
ply_trigger_pull,
quit_trigger);
return;
}
if (state->system_initialized) {
ply_trace ("system initialized so saving boot-duration file");
ply_create_directory (PLYMOUTH_TIME_DIRECTORY);
ply_progress_save_cache (state->progress,
get_cache_file_for_mode (state->mode));
} else {
ply_trace ("system not initialized so skipping saving boot-duration file");
}
state->quit_trigger = quit_trigger;
--
2.21.0