[PATCH xf86-input-libinput 2/3] Update pad modes in a workproc, not during the input thread

Peter Hutterer peter.hutterer at who-t.net
Fri Feb 24 03:10:18 UTC 2017


Updating the property directly causes us to send events from the input thread
which has some "interesting" side effects like messing up the reply order or
just crashing the server.

Schedule a work proc instead and update it whenever the server is back in the
main thread.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/xf86libinput.c | 76 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 62 insertions(+), 14 deletions(-)

diff --git a/src/xf86libinput.c b/src/xf86libinput.c
index c1214b7..ef03d3e 100644
--- a/src/xf86libinput.c
+++ b/src/xf86libinput.c
@@ -3389,17 +3389,43 @@ static Atom prop_float;
 static Atom prop_device;
 static Atom prop_product_id;
 
-static inline void
-update_mode_prop(InputInfoPtr pInfo,
-		 struct libinput_event_tablet_pad *event)
-{
-	struct xf86libinput *driver_data = pInfo->private;
+struct mode_prop_state {
+	int deviceid;
+	InputInfoPtr pInfo;
+
 	struct libinput_tablet_pad_mode_group *group;
 	unsigned int mode;
 	unsigned int idx;
+};
+
+static Bool
+update_mode_prop_cb(ClientPtr client, pointer closure)
+{
+	struct mode_prop_state *state = closure;
+	InputInfoPtr pInfo = state->pInfo, tmp;
+	struct xf86libinput *driver_data = pInfo->private;
+	BOOL found = FALSE;
 	XIPropertyValuePtr val;
 	int rc;
 	unsigned char groups[4] = {0};
+	struct libinput_tablet_pad_mode_group *group = state->group;
+	unsigned int mode = state->mode;
+	unsigned int idx = state->idx;
+
+	if (idx >= ARRAY_SIZE(groups))
+		goto out;
+
+	/* The device may have gotten removed before the WorkProc was
+	 * scheduled. X reuses deviceids, but if the pointer value and
+	 * device ID are what we had before, we're good */
+	nt_list_for_each_entry(tmp, xf86FirstLocalDevice(), next) {
+		if (tmp->dev->id == state->deviceid && tmp == pInfo) {
+			found = TRUE;
+			break;
+		}
+	}
+	if (!found)
+		goto out;
 
 	rc = XIGetDeviceProperty(pInfo->dev,
 				 prop_mode_groups,
@@ -3407,18 +3433,12 @@ update_mode_prop(InputInfoPtr pInfo,
 	if (rc != Success ||
 	    val->format != 8 ||
 	    val->size <= 0)
-		return;
+		goto out;
 
 	memcpy(groups, (unsigned char*)val->data, val->size);
 
-	group = libinput_event_tablet_pad_get_mode_group(event);
-	mode = libinput_event_tablet_pad_get_mode(event);
-	idx = libinput_tablet_pad_mode_group_get_index(group);
-	if (idx >= ARRAY_SIZE(groups))
-		return;
-
 	if (groups[idx] == mode)
-		return;
+		goto out;
 
 	groups[idx] = mode;
 
@@ -3431,8 +3451,36 @@ update_mode_prop(InputInfoPtr pInfo,
 				    groups,
 				    TRUE);
 	driver_data->allow_mode_group_updates = false;
-	if (rc != Success)
+
+out:
+	libinput_tablet_pad_mode_group_unref(group);
+	free(state);
+	return TRUE;
+}
+
+static inline void
+update_mode_prop(InputInfoPtr pInfo,
+		 struct libinput_event_tablet_pad *event)
+{
+	struct libinput_tablet_pad_mode_group *group;
+	struct mode_prop_state *state;
+
+	state = calloc(1, sizeof(*state));
+	if (!state)
 		return;
+
+	state->deviceid = pInfo->dev->id;
+	state->pInfo = pInfo;
+
+	group = libinput_event_tablet_pad_get_mode_group(event);
+
+	state->group = libinput_tablet_pad_mode_group_ref(group);
+	state->mode = libinput_event_tablet_pad_get_mode(event);
+	state->idx = libinput_tablet_pad_mode_group_get_index(group);
+
+	/* Schedule a WorkProc so we don't update from within the input
+	   thread */
+	QueueWorkProc(update_mode_prop_cb, serverClient, state);
 }
 
 static inline BOOL
-- 
2.9.3



More information about the xorg-devel mailing list