Hi
This series implements device management for logind. A session can now request
device access directly via logind dbus APIs. It extends the
org.freedesktop.login1.Session interface. The already existing interface is
described at:
http://www.freedesktop.org/wiki/Software/systemd/logind/
The reason for this series and the basic idea is discussed on:
http://dvdhrm.wordpress.com/2013/08/25/sane-session-switching/
If someone is not familiar with session-management and, more importantly,
session-switching, I summarized it at:
http://dvdhrm.wordpress.com/2013/08/24/session-management-on-linux/
http://dvdhrm.wordpress.com/2013/08/24/how-vt-switching-works/
Ok, feel free to dismiss the rest of this mail and look directly at the patches.
The commit-messages explain everything in detail. For all who are not familiar
with the systemd code-base, a summary can be found below.
Feedback welcome! I am open for any suggestions.
Tests, examples and more will be available at https://github.com/dvdhrm/libnovt
once the API stabilized.
Regards
David
CC: wayland-devel@fdo for weston-launch development.
The following calls are introduced by this series. They are added to the logind
dbus API for sessions. Hence, each call implicitly operates on a given session
and thus does not have to be passed as argument.
These methods are added:
RequestDevice(const char *node, int *fd_out, bool *paused_out):
logind tries to open a device node in /dev/ (@node) for the caller. It
checks that it is assigned to the seat of the caller, has the uaccess
flags set and then opens the fd and passes it back via @fd_out. The
@paused_out field will notify the caller whether the device is currently
paused or active.
Remarks:
- you cannot open a node twice in parallel
- you must use the canonical device-node (the one from devtmpfs) and
returned by udev_device_get_devnode(). No other nodes can be
supported; clients could trigger OOM otherwise
- logind keeps a copy of @fd internally to revoke access once the
session becomes inactive
ReleaseDevice(const char *node):
logind closes the device that was previously requested via
RequestDevice(). It revokes access from the fd and closes it internally.
The caller still has their own fd, but it will be useless. But they
obviously need to close() it theirself.
You may call RequestDevice() on the same node again, once you released
it.
As long as a process owns a device, it is notified via dbus signals about state
changes:
PauseDevice(const char *node, const char *type):
logind sends this event whenever the device is paused or released. @node
contains the device-node passed to RequestDevice() and is unique. @type
is gone if the device was closed or removed from the seat. A
compositor normally gets a udev remove event at the same time. They
should treat it similarly.
@type is force if the device was forcibly paused by logind. A
compositor normally gets EACCES or EPERM simultaneously from any
syscalls it tries on the fd. Hence, it is adviced to handle EACCES/EPERM
the same as a PauseDevice(force) signal from systemd.
Last but not least, there is pause as @type. This is a kind request by
logind to the compositor to pause the device. A compositor gets a short
timeout to react to this event, cleanup everything and acknowledge the
signal via a call to PauseDeviceComplete(). If it doesn't react in a
timely manner, a PauseDevice(force) event will be sent.
ResumeDevice(const char *node, int *fd_out):
For every device requested via RequestDevice(), logind sends this event
whenever the device is resumed. It also puts a new file-descriptor into
@fd_out. A compositor is advised to close its old fd and use the new
one. For some device-types (namely evdev) it *must* use the new fd, as
the old one is revoked. For other device-types (namely DRM) both will
actually be the same as access can be restored.
Compositors are allowed to rely on this behavior for DRM. That is, if
it's a DRM device, they can close the new fd and keep the old one
(they're actually just dup()'ed). This allows them to retain their DRM
state.
Methods to acknowledge some signals are:
PauseDeviceComplete(const char *node):
As mentioned above in PauseDevice, this is a method that can be called
by compositors to react to a PauseDevice(pause) request. After it is
called, the given device will be paused.
Note that device-management is available on all sessions regardless their type
and state. Moreover, device-state follows session-state but might also be paused
for other reasons that are currently not defined. This means, whenever a session
is