434 lines
16 KiB
Diff
434 lines
16 KiB
Diff
From 5d301b8aecc286d6ec7e92b0864d66360ea57205 Mon Sep 17 00:00:00 2001
|
|
From: David Herrmann <dh.herrmann@gmail.com>
|
|
Date: Mon, 22 Sep 2014 17:34:13 +0200
|
|
Subject: [PATCH] terminal: make evdev logind-matches per session
|
|
|
|
Instead of adding matches per device, we now add logind matches per
|
|
session. This reduces the number of matches considerably and saves
|
|
resources.
|
|
---
|
|
src/libsystemd-terminal/idev-evdev.c | 170 ++++++++------------------------
|
|
src/libsystemd-terminal/idev-internal.h | 4 +
|
|
src/libsystemd-terminal/idev.c | 114 +++++++++++++++++++++
|
|
3 files changed, 158 insertions(+), 130 deletions(-)
|
|
|
|
diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c
|
|
index 719e18c316..63fa89e47d 100644
|
|
--- a/src/libsystemd-terminal/idev-evdev.c
|
|
+++ b/src/libsystemd-terminal/idev-evdev.c
|
|
@@ -60,9 +60,6 @@ struct unmanaged_evdev {
|
|
struct managed_evdev {
|
|
idev_evdev evdev;
|
|
dev_t devnum;
|
|
-
|
|
- sd_bus_slot *slot_pause_device;
|
|
- sd_bus_slot *slot_resume_device;
|
|
sd_bus_slot *slot_take_device;
|
|
|
|
bool requested : 1; /* TakeDevice() was sent */
|
|
@@ -580,7 +577,7 @@ static int managed_evdev_take_device_fn(sd_bus *bus,
|
|
return 0;
|
|
}
|
|
|
|
-static void managed_evdev_resume(idev_element *e) {
|
|
+static void managed_evdev_enable(idev_element *e) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
|
managed_evdev *em = managed_evdev_from_element(e);
|
|
idev_session *s = e->session;
|
|
@@ -628,7 +625,7 @@ error:
|
|
s->name, e->name, strerror(-r));
|
|
}
|
|
|
|
-static void managed_evdev_pause(idev_element *e) {
|
|
+static void managed_evdev_disable(idev_element *e) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
|
managed_evdev *em = managed_evdev_from_element(e);
|
|
idev_session *s = e->session;
|
|
@@ -686,24 +683,45 @@ static void managed_evdev_pause(idev_element *e) {
|
|
s->name, e->name, strerror(-r));
|
|
}
|
|
|
|
-static int managed_evdev_pause_device_fn(sd_bus *bus,
|
|
- sd_bus_message *signal,
|
|
- void *userdata,
|
|
- sd_bus_error *ret_error) {
|
|
- managed_evdev *em = userdata;
|
|
- idev_element *e = &em->evdev.element;
|
|
+static void managed_evdev_resume(idev_element *e, int fd) {
|
|
+ managed_evdev *em = managed_evdev_from_element(e);
|
|
+ idev_session *s = e->session;
|
|
+ int r;
|
|
+
|
|
+ /*
|
|
+ * We get ResumeDevice signals whenever logind resumed a previously
|
|
+ * paused device. The arguments contain the major/minor number of the
|
|
+ * related device and a new file-descriptor for the freshly opened
|
|
+ * device-node. We take the file-descriptor and immediately resume the
|
|
+ * device.
|
|
+ */
|
|
+
|
|
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
|
+ if (fd < 0) {
|
|
+ log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
|
|
+ s->name, e->name);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ r = idev_evdev_resume(&em->evdev, fd);
|
|
+ if (r < 0)
|
|
+ log_debug("idev-evdev: %s/%s: cannot resume: %s",
|
|
+ s->name, e->name, strerror(-r));
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void managed_evdev_pause(idev_element *e, const char *mode) {
|
|
+ managed_evdev *em = managed_evdev_from_element(e);
|
|
idev_session *s = e->session;
|
|
idev_context *c = s->context;
|
|
- uint32_t major, minor;
|
|
- const char *mode;
|
|
int r;
|
|
|
|
/*
|
|
* We get PauseDevice() signals from logind whenever a device we
|
|
* requested was, or is about to be, paused. Arguments are major/minor
|
|
* number of the device and the mode of the operation.
|
|
- * In case the event is not about our device, we ignore it. Otherwise,
|
|
- * we treat it as asynchronous access-revocation (as if we got HUP on
|
|
+ * We treat it as asynchronous access-revocation (as if we got HUP on
|
|
* the device fd). Note that we might have already treated the HUP
|
|
* event via EPOLLHUP, whichever comes first.
|
|
*
|
|
@@ -728,17 +746,6 @@ static int managed_evdev_pause_device_fn(sd_bus *bus,
|
|
* acknowledge the request.
|
|
*/
|
|
|
|
- r = sd_bus_message_read(signal, "uus", &major, &minor, &mode);
|
|
- if (r < 0) {
|
|
- log_debug("idev-evdev: %s/%s: erroneous PauseDevice signal",
|
|
- s->name, e->name);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- /* not our device? */
|
|
- if (makedev(major, minor) != em->devnum)
|
|
- return 0;
|
|
-
|
|
idev_evdev_pause(&em->evdev, true);
|
|
|
|
if (streq(mode, "pause")) {
|
|
@@ -763,7 +770,7 @@ static int managed_evdev_pause_device_fn(sd_bus *bus,
|
|
"org.freedesktop.login1.Session",
|
|
"PauseDeviceComplete");
|
|
if (r >= 0) {
|
|
- r = sd_bus_message_append(m, "uu", major, minor);
|
|
+ r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
|
|
if (r >= 0)
|
|
r = sd_bus_send(c->sysbus, m, NULL);
|
|
}
|
|
@@ -772,99 +779,6 @@ static int managed_evdev_pause_device_fn(sd_bus *bus,
|
|
log_debug("idev-evdev: %s/%s: cannot send PauseDeviceComplete: %s",
|
|
s->name, e->name, strerror(-r));
|
|
}
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int managed_evdev_resume_device_fn(sd_bus *bus,
|
|
- sd_bus_message *signal,
|
|
- void *userdata,
|
|
- sd_bus_error *ret_error) {
|
|
- managed_evdev *em = userdata;
|
|
- idev_element *e = &em->evdev.element;
|
|
- idev_session *s = e->session;
|
|
- uint32_t major, minor;
|
|
- int r, fd;
|
|
-
|
|
- /*
|
|
- * We get ResumeDevice signals whenever logind resumed a previously
|
|
- * paused device. The arguments contain the major/minor number of the
|
|
- * related device and a new file-descriptor for the freshly opened
|
|
- * device-node.
|
|
- * If the signal is not about our device, we simply ignore it.
|
|
- * Otherwise, we take the file-descriptor and immediately resume the
|
|
- * device.
|
|
- */
|
|
-
|
|
- r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd);
|
|
- if (r < 0) {
|
|
- log_debug("idev-evdev: %s/%s: erroneous ResumeDevice signal",
|
|
- s->name, e->name);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- /* not our device? */
|
|
- if (makedev(major, minor) != em->devnum)
|
|
- return 0;
|
|
-
|
|
- fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
|
- if (fd < 0) {
|
|
- log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
|
|
- s->name, e->name);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- r = idev_evdev_resume(&em->evdev, fd);
|
|
- if (r < 0)
|
|
- log_debug("idev-evdev: %s/%s: cannot resume: %s",
|
|
- s->name, e->name, strerror(-r));
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int managed_evdev_setup_bus(managed_evdev *em) {
|
|
- idev_element *e = &em->evdev.element;
|
|
- idev_session *s = e->session;
|
|
- idev_context *c = s->context;
|
|
- _cleanup_free_ char *match = NULL;
|
|
- int r;
|
|
-
|
|
- match = strjoin("type='signal',"
|
|
- "sender='org.freedesktop.login1',"
|
|
- "interface='org.freedesktop.login1.Session',"
|
|
- "member='PauseDevice',"
|
|
- "path='", s->path, "'",
|
|
- NULL);
|
|
- if (!match)
|
|
- return -ENOMEM;
|
|
-
|
|
- r = sd_bus_add_match(c->sysbus,
|
|
- &em->slot_pause_device,
|
|
- match,
|
|
- managed_evdev_pause_device_fn,
|
|
- em);
|
|
- if (r < 0)
|
|
- return r;
|
|
-
|
|
- free(match);
|
|
- match = strjoin("type='signal',"
|
|
- "sender='org.freedesktop.login1',"
|
|
- "interface='org.freedesktop.login1.Session',"
|
|
- "member='ResumeDevice',"
|
|
- "path='", s->path, "'",
|
|
- NULL);
|
|
- if (!match)
|
|
- return -ENOMEM;
|
|
-
|
|
- r = sd_bus_add_match(c->sysbus,
|
|
- &em->slot_resume_device,
|
|
- match,
|
|
- managed_evdev_resume_device_fn,
|
|
- em);
|
|
- if (r < 0)
|
|
- return r;
|
|
-
|
|
- return 0;
|
|
}
|
|
|
|
static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
|
|
@@ -893,10 +807,6 @@ static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_de
|
|
em->evdev = IDEV_EVDEV_INIT(&managed_evdev_vtable, s);
|
|
em->devnum = devnum;
|
|
|
|
- r = managed_evdev_setup_bus(em);
|
|
- if (r < 0)
|
|
- return r;
|
|
-
|
|
r = idev_element_add(e, name);
|
|
if (r < 0)
|
|
return r;
|
|
@@ -910,18 +820,18 @@ static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_de
|
|
static void managed_evdev_free(idev_element *e) {
|
|
managed_evdev *em = managed_evdev_from_element(e);
|
|
|
|
- em->slot_resume_device = sd_bus_slot_unref(em->slot_resume_device);
|
|
- em->slot_pause_device = sd_bus_slot_unref(em->slot_pause_device);
|
|
idev_evdev_destroy(&em->evdev);
|
|
free(em);
|
|
}
|
|
|
|
static const idev_element_vtable managed_evdev_vtable = {
|
|
.free = managed_evdev_free,
|
|
- .enable = managed_evdev_resume,
|
|
- .disable = managed_evdev_pause,
|
|
- .open = managed_evdev_resume,
|
|
- .close = managed_evdev_pause,
|
|
+ .enable = managed_evdev_enable,
|
|
+ .disable = managed_evdev_disable,
|
|
+ .open = managed_evdev_enable,
|
|
+ .close = managed_evdev_disable,
|
|
+ .resume = managed_evdev_resume,
|
|
+ .pause = managed_evdev_pause,
|
|
};
|
|
|
|
/*
|
|
diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h
|
|
index c416f4fadd..a159aef211 100644
|
|
--- a/src/libsystemd-terminal/idev-internal.h
|
|
+++ b/src/libsystemd-terminal/idev-internal.h
|
|
@@ -116,6 +116,8 @@ struct idev_element_vtable {
|
|
void (*disable) (idev_element *e);
|
|
void (*open) (idev_element *e);
|
|
void (*close) (idev_element *e);
|
|
+ void (*resume) (idev_element *e, int fd);
|
|
+ void (*pause) (idev_element *e, const char *mode);
|
|
void (*feedback) (idev_element *e, idev_data *data);
|
|
};
|
|
|
|
@@ -155,6 +157,8 @@ struct idev_session {
|
|
idev_context *context;
|
|
char *name;
|
|
char *path;
|
|
+ sd_bus_slot *slot_resume_device;
|
|
+ sd_bus_slot *slot_pause_device;
|
|
|
|
Hashmap *element_map;
|
|
Hashmap *device_map;
|
|
diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c
|
|
index 8592930662..e979b608b6 100644
|
|
--- a/src/libsystemd-terminal/idev.c
|
|
+++ b/src/libsystemd-terminal/idev.c
|
|
@@ -274,6 +274,22 @@ static void element_disable(idev_element *e) {
|
|
}
|
|
}
|
|
|
|
+static void element_resume(idev_element *e, int fd) {
|
|
+ assert(e);
|
|
+ assert(fd >= 0);
|
|
+
|
|
+ if (e->vtable->resume)
|
|
+ e->vtable->resume(e, fd);
|
|
+}
|
|
+
|
|
+static void element_pause(idev_element *e, const char *mode) {
|
|
+ assert(e);
|
|
+ assert(mode);
|
|
+
|
|
+ if (e->vtable->pause)
|
|
+ e->vtable->pause(e, mode);
|
|
+}
|
|
+
|
|
/*
|
|
* Sessions
|
|
*/
|
|
@@ -417,6 +433,98 @@ idev_session *idev_find_session(idev_context *c, const char *name) {
|
|
return hashmap_get(c->session_map, name);
|
|
}
|
|
|
|
+static int session_resume_device_fn(sd_bus *bus,
|
|
+ sd_bus_message *signal,
|
|
+ void *userdata,
|
|
+ sd_bus_error *ret_error) {
|
|
+ idev_session *s = userdata;
|
|
+ idev_element *e;
|
|
+ uint32_t major, minor;
|
|
+ int r, fd;
|
|
+
|
|
+ r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd);
|
|
+ if (r < 0) {
|
|
+ log_debug("idev: %s: erroneous ResumeDevice signal", s->name);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ e = idev_find_evdev(s, makedev(major, minor));
|
|
+ if (!e)
|
|
+ return 0;
|
|
+
|
|
+ element_resume(e, fd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int session_pause_device_fn(sd_bus *bus,
|
|
+ sd_bus_message *signal,
|
|
+ void *userdata,
|
|
+ sd_bus_error *ret_error) {
|
|
+ idev_session *s = userdata;
|
|
+ idev_element *e;
|
|
+ uint32_t major, minor;
|
|
+ const char *mode;
|
|
+ int r;
|
|
+
|
|
+ r = sd_bus_message_read(signal, "uus", &major, &minor, &mode);
|
|
+ if (r < 0) {
|
|
+ log_debug("idev: %s: erroneous PauseDevice signal", s->name);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ e = idev_find_evdev(s, makedev(major, minor));
|
|
+ if (!e)
|
|
+ return 0;
|
|
+
|
|
+ element_pause(e, mode);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int session_setup_bus(idev_session *s) {
|
|
+ _cleanup_free_ char *match = NULL;
|
|
+ int r;
|
|
+
|
|
+ if (!s->managed)
|
|
+ return 0;
|
|
+
|
|
+ match = strjoin("type='signal',"
|
|
+ "sender='org.freedesktop.login1',"
|
|
+ "interface='org.freedesktop.login1.Session',"
|
|
+ "member='ResumeDevice',"
|
|
+ "path='", s->path, "'",
|
|
+ NULL);
|
|
+ if (!match)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ r = sd_bus_add_match(s->context->sysbus,
|
|
+ &s->slot_resume_device,
|
|
+ match,
|
|
+ session_resume_device_fn,
|
|
+ s);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ free(match);
|
|
+ match = strjoin("type='signal',"
|
|
+ "sender='org.freedesktop.login1',"
|
|
+ "interface='org.freedesktop.login1.Session',"
|
|
+ "member='PauseDevice',"
|
|
+ "path='", s->path, "'",
|
|
+ NULL);
|
|
+ if (!match)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ r = sd_bus_add_match(s->context->sysbus,
|
|
+ &s->slot_pause_device,
|
|
+ match,
|
|
+ session_pause_device_fn,
|
|
+ s);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int idev_session_new(idev_session **out,
|
|
idev_context *c,
|
|
unsigned int flags,
|
|
@@ -462,6 +570,10 @@ int idev_session_new(idev_session **out,
|
|
if (!s->device_map)
|
|
return -ENOMEM;
|
|
|
|
+ r = session_setup_bus(s);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
r = hashmap_put(c->session_map, s->name, s);
|
|
if (r < 0)
|
|
return r;
|
|
@@ -485,6 +597,8 @@ idev_session *idev_session_free(idev_session *s) {
|
|
if (s->name)
|
|
hashmap_remove_value(s->context->session_map, s->name, s);
|
|
|
|
+ s->slot_pause_device = sd_bus_slot_unref(s->slot_pause_device);
|
|
+ s->slot_resume_device = sd_bus_slot_unref(s->slot_resume_device);
|
|
s->context = idev_context_unref(s->context);
|
|
hashmap_free(s->device_map);
|
|
hashmap_free(s->element_map);
|