mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-05-04 23:38:01 +02:00
libei: free all devices on context removal
This requires a new state so we can differ between having a connection and not having one. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
11be8c7a2f
commit
1c5d6c1e2b
3 changed files with 71 additions and 36 deletions
|
|
@ -111,8 +111,11 @@ ei_device_add(struct ei_device *device)
|
|||
_public_ void
|
||||
ei_device_remove(struct ei_device *device)
|
||||
{
|
||||
ei_remove_device(device);
|
||||
if (device->state == EI_DEVICE_STATE_REMOVED)
|
||||
return;
|
||||
|
||||
device->state = EI_DEVICE_STATE_REMOVED;
|
||||
ei_remove_device(device);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@ struct ei_backend_interface {
|
|||
};
|
||||
|
||||
enum ei_state {
|
||||
EI_STATE_NEW, /* No backend yet */
|
||||
EI_STATE_BACKEND, /* We have a backend */
|
||||
EI_STATE_CONNECTING, /* client requested connect */
|
||||
EI_STATE_CONNECTED, /* server has sent connect */
|
||||
EI_STATE_DISCONNECTING, /* in the process of cleaning up */
|
||||
EI_STATE_DISCONNECTED,
|
||||
};
|
||||
|
||||
|
|
|
|||
100
src/libei.c
100
src/libei.c
|
|
@ -108,9 +108,13 @@ OBJECT_IMPLEMENT_GETTER(ei_event, type, enum ei_event_type);
|
|||
_public_
|
||||
OBJECT_IMPLEMENT_GETTER(ei_event, device, struct ei_device*);
|
||||
|
||||
static void
|
||||
ei_disconnect(struct ei *ei);
|
||||
|
||||
static void
|
||||
ei_destroy(struct ei *ei)
|
||||
{
|
||||
ei_disconnect(ei);
|
||||
ei->logger = logger_unref(ei->logger);
|
||||
if (ei->backend_interface.destroy)
|
||||
ei->backend_interface.destroy(ei, ei->backend);
|
||||
|
|
@ -134,7 +138,7 @@ ei_new(void *user_data)
|
|||
{
|
||||
_cleanup_ei_ struct ei *ei = ei_create(NULL);
|
||||
|
||||
ei->state = EI_STATE_BACKEND;
|
||||
ei->state = EI_STATE_NEW;
|
||||
list_init(&ei->event_queue);
|
||||
list_init(&ei->devices);
|
||||
|
||||
|
|
@ -231,7 +235,8 @@ connection_send_msg(struct ei *ei, const ClientMessage *msg)
|
|||
static int
|
||||
connection_send_connect(struct ei *ei)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -246,7 +251,8 @@ connection_send_connect(struct ei *ei)
|
|||
static int
|
||||
connection_send_disconnect(struct ei *ei)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -261,7 +267,8 @@ connection_send_disconnect(struct ei *ei)
|
|||
static int
|
||||
connection_send_add(struct ei *ei, struct ei_device *device)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -279,7 +286,8 @@ connection_send_add(struct ei *ei, struct ei_device *device)
|
|||
static int
|
||||
connection_send_remove(struct ei *ei, struct ei_device *device)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -296,7 +304,8 @@ connection_send_remove(struct ei *ei, struct ei_device *device)
|
|||
static int
|
||||
connection_send_rel(struct ei *ei, struct ei_device *device, int32_t x, int32_t y)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -316,7 +325,8 @@ static int
|
|||
connection_send_button(struct ei *ei, struct ei_device *device,
|
||||
uint32_t b, bool is_press)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -336,7 +346,8 @@ static int
|
|||
connection_send_key(struct ei *ei, struct ei_device *device,
|
||||
uint32_t k, bool is_press)
|
||||
{
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
if (ei->state == EI_STATE_NEW ||
|
||||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
|
|
@ -355,11 +366,28 @@ connection_send_key(struct ei *ei, struct ei_device *device,
|
|||
static void
|
||||
ei_disconnect(struct ei *ei)
|
||||
{
|
||||
connection_send_disconnect(ei);
|
||||
/* FIXME: unroll the devices here */
|
||||
ei_queue_disconnect_event(ei);
|
||||
if (ei->state == EI_STATE_DISCONNECTED ||
|
||||
ei->state == EI_STATE_DISCONNECTING)
|
||||
return;
|
||||
|
||||
enum ei_state state = ei->state;
|
||||
|
||||
/* We need the disconnecting state to be re-entrant
|
||||
ei_device_remove() may call ei_disconnect() on a socket error */
|
||||
ei->state = EI_STATE_DISCONNECTING;
|
||||
|
||||
struct ei_device *d, *tmp;
|
||||
list_for_each_safe(d, tmp, &ei->devices, link) {
|
||||
ei_device_remove(d);
|
||||
}
|
||||
|
||||
if (state != EI_STATE_NEW) {
|
||||
connection_send_disconnect(ei);
|
||||
ei_queue_disconnect_event(ei);
|
||||
}
|
||||
ei->state = EI_STATE_DISCONNECTED;
|
||||
source_remove(ei->source);
|
||||
if (ei->source)
|
||||
source_remove(ei->source);
|
||||
ei->source = source_unref(ei->source);
|
||||
}
|
||||
|
||||
|
|
@ -372,6 +400,8 @@ ei_add_device(struct ei_device *device)
|
|||
ei_disconnect(ei);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ei_device_ref(device);
|
||||
list_append(&ei->devices, &device->link);
|
||||
|
||||
return 0;
|
||||
|
|
@ -382,15 +412,13 @@ ei_remove_device(struct ei_device *device)
|
|||
{
|
||||
struct ei *ei = ei_device_get_context(device);
|
||||
int rc = connection_send_remove(ei, device);
|
||||
if (rc) {
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
}
|
||||
|
||||
list_remove(&device->link);
|
||||
ei_device_unref(device);
|
||||
|
||||
return 0;
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -669,6 +697,8 @@ connection_dispatch(struct source *source, void *userdata)
|
|||
idx += len;
|
||||
|
||||
switch (ei->state) {
|
||||
case EI_STATE_NEW:
|
||||
abort();
|
||||
case EI_STATE_BACKEND:
|
||||
rc = connection_new_handle_msg(ei, msg);
|
||||
break;
|
||||
|
|
@ -678,6 +708,7 @@ connection_dispatch(struct source *source, void *userdata)
|
|||
case EI_STATE_CONNECTED:
|
||||
rc = connection_connected_handle_msg(ei, msg);
|
||||
break;
|
||||
case EI_STATE_DISCONNECTING:
|
||||
case EI_STATE_DISCONNECTED:
|
||||
abort();
|
||||
}
|
||||
|
|
@ -688,10 +719,12 @@ error:
|
|||
ei_disconnect(ei);
|
||||
|
||||
static const char *states[] = {
|
||||
"NEW",
|
||||
"BACKEND",
|
||||
"CONNECTING",
|
||||
"CONNECTED",
|
||||
"DISCONNECTED",
|
||||
"DISCONNECTING",
|
||||
};
|
||||
if (rc)
|
||||
log_warn(ei, "Connnection error: %s\n", strerror(-rc));
|
||||
|
|
@ -708,6 +741,7 @@ ei_set_connection(struct ei *ei, int fd)
|
|||
return -ENOMEM;
|
||||
|
||||
ei->source = source_ref(source);
|
||||
ei->state = EI_STATE_BACKEND;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -715,7 +749,7 @@ ei_set_connection(struct ei *ei, int fd)
|
|||
_public_ void
|
||||
ei_configure_name(struct ei *ei, const char *name)
|
||||
{
|
||||
if (ei->state != EI_STATE_BACKEND)
|
||||
if (ei->state != EI_STATE_NEW)
|
||||
return;
|
||||
|
||||
if (strlen(name) > 1024)
|
||||
|
|
@ -731,10 +765,9 @@ ei_configure_name(struct ei *ei, const char *name)
|
|||
static MunitResult
|
||||
test_init_unref(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
/* need to alloc here so unref can free */
|
||||
struct ei *ei = ei_new(NULL);
|
||||
|
||||
munit_assert_int(ei->state, ==, EI_STATE_BACKEND);
|
||||
munit_assert_int(ei->state, ==, EI_STATE_NEW);
|
||||
munit_assert(list_empty(&ei->event_queue));
|
||||
munit_assert(list_empty(&ei->devices));
|
||||
|
||||
|
|
@ -745,7 +778,6 @@ test_init_unref(const MunitParameter params[], void *user_data)
|
|||
munit_assert_ptr_equal(ei, refd);
|
||||
munit_assert_int(ei->object.refcount, ==, 2);
|
||||
|
||||
|
||||
struct ei *unrefd = ei_unref(ei);
|
||||
munit_assert_null(unrefd);
|
||||
|
||||
|
|
@ -758,31 +790,29 @@ test_init_unref(const MunitParameter params[], void *user_data)
|
|||
static MunitResult
|
||||
test_configure_name(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
struct ei ei = {
|
||||
.state = EI_STATE_NEW,
|
||||
};
|
||||
struct ei *ei = ei_new(NULL);
|
||||
|
||||
ei_configure_name(&ei, "foo");
|
||||
munit_assert_string_equal(ei.name, "foo");
|
||||
ei_configure_name(&ei, "bar");
|
||||
munit_assert_string_equal(ei.name, "bar");
|
||||
ei_configure_name(ei, "foo");
|
||||
munit_assert_string_equal(ei->name, "foo");
|
||||
ei_configure_name(ei, "bar");
|
||||
munit_assert_string_equal(ei->name, "bar");
|
||||
|
||||
/* ignore names that are too long */
|
||||
char buf[1200] = {0};
|
||||
memset(buf, 'a', sizeof(buf) - 1);
|
||||
ei_configure_name(&ei, buf);
|
||||
munit_assert_string_equal(ei.name, "bar");
|
||||
ei_configure_name(ei, buf);
|
||||
munit_assert_string_equal(ei->name, "bar");
|
||||
|
||||
/* ignore names in all other states */
|
||||
for (enum ei_state state = EI_STATE_HELLO + 1;
|
||||
for (enum ei_state state = EI_STATE_NEW + 1;
|
||||
state <= EI_STATE_DISCONNECTED;
|
||||
state++) {
|
||||
ei.state = state;
|
||||
ei_configure_name(&ei, "expect ignored");
|
||||
munit_assert_string_equal(ei.name, "bar");
|
||||
ei->state = state;
|
||||
ei_configure_name(ei, "expect ignored");
|
||||
munit_assert_string_equal(ei->name, "bar");
|
||||
}
|
||||
|
||||
free(ei.name);
|
||||
ei_unref(ei);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue