[systemd-devel] [RFC 08/12] gfx: add monitor
Lennart Poettering
lennart at poettering.net
Wed Nov 27 14:34:15 PST 2013
On Wed, 27.11.13 19:48, David Herrmann (dh.herrmann at gmail.com) wrote:
> While all previous sd-gfx interfaces are self-contained and can be used
> directly on selected devices, this adds an interface to connect them all
> together. The sd_gfx_monitor can be used to monitor a session for device
> hotplugging and other device events. It is optional but is supposed to be
> the foundation of all systemd-helpers that use sd-gfx.
>
> The main function of sd_gfx_monitor is to watch the system for udev-events
> of gpus and keyboards. For each of them, an sd_gfx_card or sd_gfx_kbd
> device is created and advertised to the application. Furthermore,
> systemd-localed integration is provided so keymap changes are immediately
> noticed and applied to active sd_gfx_kbd devices.
>
> An sd_gfx_monitor can run in two modes:
> - system mode: In system mode, no dbus, no logind and localed are assumed
> to be running and seat-information is ignored. This mode
> allows to run applications in initrds or emergency
> situations. It simply takes all devices it can find and
> tries to use them. However, this obviously requires to be
> root, otherwise, devices cannot be accessed.
> - session mode: In session mode, the monitor assumes to be running in an
> logind session. If not, it returns an error. The monitor
> will call TakeControl on the active session and get
> device-access via logind. Only devices attached to the
> session will be used and no you're not required to be
> root. The caller is responsible of setting up the session
> before spawning the monitor.
>
> Note that monitor setup is a blocking call as it is usually called during
> application setup (and making that async would have no gain). But at
> runtime, the monitor runs all dbus-calls and other calls asynchronously.
>
> The sd_gfx_monitor interface is designed for fallbacks and basic system
> applications. It does not allow per-device configurations or any advanced
> eye-candy. It is trimmed for usability and simplicity, and it is optimized
> for fallback/emergency situations. Thus, the monitor provides some basic
> configuration options via the kernel command-line. systemd.gpus= allows to
> filter the GPUs to be used (by default, *all* connected GPUs are used
> together). systemd.keymap= allows to change the keymap in case localed is
> configured incorrectly.
>
> The sd_gfx_monitor interfaces has the nice side-effect that all
> applications using it will share the same configuration. They will have
> the same monitor-setup, the same keymap setup and use the same devices. So
> if you system-boot fails, you can set systemd.XY="" to boot with a working
> configuration and all systemd-internal applications will just work.
>
> If we ever export sd-gfx, most users probably want more configurability
> (like per-device keymaps) and thus will not use sd_gfx_monitor. However,
> for all fallbacks, it is the perfect base.
Hmm, this bit sounds a bit too high-level for including it in a library,
no? I mean, we can certainly share this bit inside of systemd, but this
sounds too specialized to ever become a public lib, no?
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_UNIX_FD, &fd);
> + if (r < 0)
> + goto error;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_BOOLEAN, &paused);
> + if (r < 0)
> + goto error;
Why in two steps? sd_bus_message_read(m, "hb", &fd, &paused) should work too?
> +static int gfx_logind_resume_fn(sd_bus *bus, sd_bus_message *m, void *data, sd_bus_error *err) {
> + sd_gfx_monitor *mon = data;
> + gfx_device *dev;
> + int r, fd;
> + uint32_t major, minor;
> + dev_t devt;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_UINT32, &major);
> + if (r < 0)
> + goto error;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_UINT32, &minor);
> + if (r < 0)
> + goto error;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_UNIX_FD, &fd);
> + if (r < 0)
> + goto error;
Same here... One call should suffice...
> +static int gfx_logind_pause_fn(sd_bus *bus, sd_bus_message *m, void *data, sd_bus_error *err) {
> + sd_gfx_monitor *mon = data;
> + gfx_device *dev;
> + int r;
> + const char *type;
> + uint32_t major, minor;
> + dev_t devt;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_UINT32, &major);
> + if (r < 0)
> + goto error;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_UINT32, &minor);
> + if (r < 0)
> + goto error;
> +
> + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &type);
> + if (r < 0)
> + goto error;
and here...
> + r = asprintf(&v,
> + "type='signal',"
> + "sender='org.freedesktop.login1',"
> + "interface='org.freedesktop.login1.Session',"
> + "member='PauseDevice',"
> + "path='%s'",
> + mon->spath);
asprintf() is actually disgustingly slow. Not that it would matter much
int this case here, but strjoin() is much nicer and measurably faster
for simple concatenation.
> +static int gfx_logind_prepare(sd_gfx_monitor *mon) {
> + _cleanup_free_ char *sid = NULL;
> + _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
> + int r;
> +
> + sid = sd_bus_label_escape(mon->sid);
> + if (!sid)
> + return log_oom();
> +
> + r = asprintf(&mon->spath, "/org/freedesktop/login1/session/%s", sid);
> + if (r < 0)
> + goto error;
strappend() as special case of strjoin() for only two strings is even
better. Or, in this case, since you never hand out the string you can
even use strappenda()...
Lennart
--
Lennart Poettering, Red Hat
More information about the systemd-devel
mailing list