From 6fcaf7699c3b5ee1bc0a8199044a8989b2c6145f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 23 Dec 2013 14:10:56 +1000 Subject: [PATCH] udev: Refcount the seat for each device Use the seat's internal refcounting to up the reference each time we have a device using it. This fixes the issue with seats being created but never actually removed by anything. udev_seat_get_named() will now return a seat with refcount 1 for a newly created seat, or just up the refcount for the seat if it already exists. This requires that the ADDED_SEAT and REMOVED_SEAT events up the refcount of the seat as well: a device may be removed before the event is processed, without the refcount the seat would be destroyed (if it's the last device on the seat). Signed-off-by: Peter Hutterer --- src/libinput.c | 8 ++++++++ src/udev-seat.c | 36 +++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/libinput.c b/src/libinput.c index 1d99e42c..98f52edb 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -478,6 +478,10 @@ libinput_event_destroy(struct libinput_event *event) break; } + if (libinput_event_get_type(event) == LIBINPUT_EVENT_ADDED_SEAT || + libinput_event_get_type(event) == LIBINPUT_EVENT_REMOVED_SEAT) + libinput_seat_unref(((struct libinput_event_added_seat*)event)->seat); + free(event); } @@ -647,6 +651,8 @@ notify_added_seat(struct libinput_seat *seat) if (!added_seat_event) return; + libinput_seat_ref(seat); + *added_seat_event = (struct libinput_event_added_seat) { .seat = seat, }; @@ -665,6 +671,8 @@ notify_removed_seat(struct libinput_seat *seat) if (!removed_seat_event) return; + libinput_seat_ref(seat); + *removed_seat_event = (struct libinput_event_removed_seat) { .seat = seat, }; diff --git a/src/udev-seat.c b/src/udev-seat.c index a78be437..08e7ada7 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -68,8 +68,13 @@ device_added(struct udev_device *udev_device, struct udev_input *input) seat = udev_seat_get_named(input, seat_name); - if (seat == NULL) - return -1; + if (seat) + libinput_seat_ref(&seat->base); + else { + seat = udev_seat_create(input, seat_name); + if (!seat) + return -1; + } /* Use non-blocking mode so that we can loop on read on * evdev_device_data() until all events on the fd are @@ -77,18 +82,18 @@ device_added(struct udev_device *udev_device, struct udev_input *input) fd = open_restricted(libinput, devnode, O_RDWR | O_NONBLOCK); if (fd < 0) { log_info("opening input device '%s' failed (%s).\n", devnode, strerror(-fd)); - return 0; + goto error; } device = evdev_device_create(&seat->base, devnode, sysname, fd); if (device == EVDEV_UNHANDLED_DEVICE) { close_restricted(libinput, fd); log_info("not using input device '%s'.\n", devnode); - return 0; + goto error; } else if (device == NULL) { close_restricted(libinput, fd); log_info("failed to create input device '%s'.\n", devnode); - return 0; + goto error; } calibration_values = @@ -118,6 +123,10 @@ device_added(struct udev_device *udev_device, struct udev_input *input) device->output_name = strdup(output_name); return 0; +error: + if (seat) + libinput_seat_unref(&seat->base); + return 0; } static int @@ -189,6 +198,7 @@ evdev_udev_handler(void *data) device->devname, device->devnode); close_restricted(libinput, device->fd); evdev_device_remove(device); + libinput_seat_unref(&seat->base); break; } } @@ -202,13 +212,14 @@ static void udev_input_remove_devices(struct udev_input *input) { struct evdev_device *device, *next; - struct udev_seat *seat; + struct udev_seat *seat, *tmp; - list_for_each(seat, &input->base.seat_list, base.link) { + list_for_each_safe(seat, tmp, &input->base.seat_list, base.link) { list_for_each_safe(device, next, &seat->base.devices_list, base.link) { close_restricted(&input->base, device->fd); evdev_device_remove(device); + libinput_seat_unref(&seat->base); } } } @@ -278,16 +289,12 @@ udev_input_enable(struct libinput *libinput) static void udev_input_destroy(struct libinput *input) { - struct libinput_seat *seat, *next; struct udev_input *udev_input = (struct udev_input*)input; if (input == NULL) return; udev_input_disable(input); - list_for_each_safe(seat, next, &input->seat_list, link) { - libinput_seat_unref(seat); - } udev_unref(udev_input->udev); free(udev_input->seat_id); } @@ -325,12 +332,7 @@ udev_seat_get_named(struct udev_input *input, const char *seat_name) return seat; } - seat = udev_seat_create(input, seat_name); - - if (!seat) - return NULL; - - return seat; + return NULL; } static const struct libinput_interface_backend interface_backend = {