Reference count event target struct when applicable

If the target of an event is a reference counted object, such as
libinput_seat and libinput_device, make events own its own reference to
the object, releasing it when destroyed.

In order to do this, a new API requirement and function are introduced;
libinput_event_destroy(). The user is required to use
libinput_event_destroy() instead of free() after having retrieved an
event using libinput_get_event().

This fixes a race that would be triggered if a device or seat would be
added and removed before the user calling libinput_get_event().

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
Jonas Ådahl 2013-12-07 16:41:43 +01:00
parent 5836054306
commit 758e553645
2 changed files with 75 additions and 1 deletions

View file

@ -35,6 +35,12 @@
#include "evdev.h"
#include "udev-seat.h"
enum libinput_event_class {
LIBINPUT_EVENT_CLASS_BASE,
LIBINPUT_EVENT_CLASS_SEAT,
LIBINPUT_EVENT_CLASS_DEVICE,
};
struct libinput_source {
libinput_source_dispatch_t dispatch;
void *user_data;
@ -116,6 +122,48 @@ libinput_destroy(struct libinput *libinput)
free(libinput);
}
static enum libinput_event_class
libinput_event_get_class(struct libinput_event *event)
{
switch (event->type) {
case LIBINPUT_EVENT_ADDED_SEAT:
case LIBINPUT_EVENT_REMOVED_SEAT:
case LIBINPUT_EVENT_ADDED_DEVICE:
case LIBINPUT_EVENT_REMOVED_DEVICE:
return LIBINPUT_EVENT_CLASS_BASE;
case LIBINPUT_EVENT_DEVICE_REGISTER_CAPABILITY:
case LIBINPUT_EVENT_DEVICE_UNREGISTER_CAPABILITY:
case LIBINPUT_EVENT_KEYBOARD_KEY:
case LIBINPUT_EVENT_POINTER_MOTION:
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
case LIBINPUT_EVENT_POINTER_BUTTON:
case LIBINPUT_EVENT_POINTER_AXIS:
case LIBINPUT_EVENT_TOUCH_TOUCH:
return LIBINPUT_EVENT_CLASS_DEVICE;
}
/* We should never end up here. */
abort();
}
LIBINPUT_EXPORT void
libinput_event_destroy(struct libinput_event *event)
{
switch (libinput_event_get_class(event)) {
case LIBINPUT_EVENT_CLASS_BASE:
break;
case LIBINPUT_EVENT_CLASS_SEAT:
libinput_seat_unref(event->target.seat);
break;
case LIBINPUT_EVENT_CLASS_DEVICE:
libinput_device_unref(event->target.device);
break;
}
free(event);
}
int
open_restricted(struct libinput *libinput,
const char *path, int flags)
@ -546,6 +594,17 @@ libinput_post_event(struct libinput *libinput,
libinput->events_len = events_len;
}
switch (libinput_event_get_class(event)) {
case LIBINPUT_EVENT_CLASS_BASE:
break;
case LIBINPUT_EVENT_CLASS_SEAT:
libinput_seat_ref(event->target.seat);
break;
case LIBINPUT_EVENT_CLASS_DEVICE:
libinput_device_ref(event->target.device);
break;
}
libinput->events_count = events_count;
events[libinput->events_in] = event;
libinput->events_in = (libinput->events_in + 1) % libinput->events_len;

View file

@ -296,7 +296,8 @@ libinput_dispatch(struct libinput *libinput);
*
* Retrieve the next event from libinput's internal event queue.
*
* After handling the retrieved event, the caller must free it using free().
* After handling the retrieved event, the caller must destroy it using
* libinput_event_destroy().
*
* @param libinput A previously initialized libinput context
* @return The next available event, or NULL if no event is available.
@ -350,6 +351,20 @@ libinput_suspend(struct libinput *libinput);
void
libinput_destroy(struct libinput *libinput);
/**
* @defgroup event Acessing and destruction of events
*/
/**
* @ingroup event
*
* Destroy the event.
*
* @param event An event retrieved by libinput_get_event().
*/
void
libinput_event_destroy(struct libinput_event *event);
/**
* @defgroup seat Initialization and manipulation of seats
*/