diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-09-17 17:39:54 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-09-17 11:15:29 -0500 |
commit | 718d006a63f773c42106494e823250c48942cf08 (patch) | |
tree | a356a46f814df765e1a9288a3827861071ab34ec /src/login/logind.c | |
parent | 1731e34a4ebddf6e1247ad252c7a45c2c1163f42 (diff) |
logind: listen actively for session devices
Session compositors need access to fbdev, DRM and evdev devices if they
control a session. To make logind pass them to sessions, we need to
listen for them actively.
However, we avoid creating new seats for non master-of-seat devices. Only
once a seat is created, we start remembering all other session devices. If
the last master-device is removed (even if there are other non-master
devices still available), we destroy the seat. This is the current
behavior, but we need to explicitly implement it now as there may be
non-master devices in the seat->devices list.
Unlike master devices, we don't care whether our list of non-master
devices is complete. We don't export this list but use it only as cache if
sessions request these devices. Hence, if a session requests a device that
is not in the list, we will simply look it up. However, once a session
requested a device, we must be notified of "remove" udev events. So we
must link the devices somehow into the device-list.
Regarding the implementation, we now sort the device list by the "master"
flag. This guarantees that master devices are at the front and non-master
devices at the tail of the list. Thus, we can easily test whether a seat
has a master device attached.
Diffstat (limited to 'src/login/logind.c')
-rw-r--r-- | src/login/logind.c | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/src/login/logind.c b/src/login/logind.c index 4ef92b8253..29019c214b 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -151,6 +151,8 @@ void manager_free(Manager *m) { if (m->udev_seat_monitor) udev_monitor_unref(m->udev_seat_monitor); + if (m->udev_device_monitor) + udev_monitor_unref(m->udev_device_monitor); if (m->udev_vcsa_monitor) udev_monitor_unref(m->udev_vcsa_monitor); if (m->udev_button_monitor) @@ -184,7 +186,7 @@ void manager_free(Manager *m) { free(m); } -int manager_add_device(Manager *m, const char *sysfs, Device **_device) { +int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) { Device *d; assert(m); @@ -195,10 +197,13 @@ int manager_add_device(Manager *m, const char *sysfs, Device **_device) { if (_device) *_device = d; + /* we support adding master-flags, but not removing them */ + d->master = d->master || master; + return 0; } - d = device_new(m, sysfs); + d = device_new(m, sysfs, master); if (!d) return -ENOMEM; @@ -373,7 +378,8 @@ int manager_process_seat_device(Manager *m, struct udev_device *d) { } else { const char *sn; - Seat *seat; + Seat *seat = NULL; + bool master; sn = udev_device_get_property_value(d, "ID_SEAT"); if (isempty(sn)) @@ -384,16 +390,23 @@ int manager_process_seat_device(Manager *m, struct udev_device *d) { return 0; } - r = manager_add_device(m, udev_device_get_syspath(d), &device); + /* ignore non-master devices for unknown seats */ + master = udev_device_has_tag(d, "master-of-seat"); + if (!master && !(seat = hashmap_get(m->seats, sn))) + return 0; + + r = manager_add_device(m, udev_device_get_syspath(d), master, &device); if (r < 0) return r; - r = manager_add_seat(m, sn, &seat); - if (r < 0) { - if (!device->seat) - device_free(device); + if (!seat) { + r = manager_add_seat(m, sn, &seat); + if (r < 0) { + if (!device->seat) + device_free(device); - return r; + return r; + } } device_attach(device, seat); @@ -762,6 +775,22 @@ int manager_dispatch_seat_udev(Manager *m) { return r; } +static int manager_dispatch_device_udev(Manager *m) { + struct udev_device *d; + int r; + + assert(m); + + d = udev_monitor_receive_device(m->udev_device_monitor); + if (!d) + return -ENOMEM; + + r = manager_process_seat_device(m, d); + udev_device_unref(d); + + return r; +} + int manager_dispatch_vcsa_udev(Manager *m) { struct udev_device *d; int r = 0; @@ -1149,6 +1178,7 @@ static int manager_connect_udev(Manager *m) { assert(m); assert(!m->udev_seat_monitor); + assert(!m->udev_device_monitor); assert(!m->udev_vcsa_monitor); assert(!m->udev_button_monitor); @@ -1169,6 +1199,33 @@ static int manager_connect_udev(Manager *m) { if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0) return -errno; + m->udev_device_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_device_monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "input", NULL); + if (r < 0) + return r; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "graphics", NULL); + if (r < 0) + return r; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "drm", NULL); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(m->udev_device_monitor); + if (r < 0) + return r; + + m->udev_device_fd = udev_monitor_get_fd(m->udev_device_monitor); + zero(ev); + ev.events = EPOLLIN; + ev.data.u32 = FD_DEVICE_UDEV; + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_device_fd, &ev) < 0) + return -errno; + /* Don't watch keys if nobody cares */ if (m->handle_power_key != HANDLE_IGNORE || m->handle_suspend_key != HANDLE_IGNORE || @@ -1545,6 +1602,10 @@ int manager_run(Manager *m) { manager_dispatch_seat_udev(m); break; + case FD_DEVICE_UDEV: + manager_dispatch_device_udev(m); + break; + case FD_VCSA_UDEV: manager_dispatch_vcsa_udev(m); break; |