mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-08 05:40:29 +01:00
eis: revamp the internal sync callback
Identical to "ei: revamp the internal sync callback" but for libeis. In prep work for exposing some of this to the caller, this adds a new object that carries the our callbacks including the user data (if any). This is an internal system only and is only used in the handshake implementation where we don't have userdata anyway. The new approach is: the callback has an object with a done() and destroy() callback and the user data, done() is called when we receive the message from the protocol, destroy() on destroy regardless whether we got done() first. This allows a caller to clean up user data even where the callback was not triggered because we got disconnected first. Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
This commit is contained in:
parent
95eb3c4bb3
commit
2cc5e56e28
4 changed files with 95 additions and 28 deletions
|
|
@ -80,11 +80,10 @@ ei_connection_sync_callback_new(struct ei *ei,
|
|||
ei_connection_sync_callback_done_t done,
|
||||
ei_connection_sync_callback_destroy_t destroy,
|
||||
void *user_data);
|
||||
struct ei *
|
||||
ei_connection_sync_callback_get_context(struct ei_connection_sync_callback *callback);
|
||||
|
||||
OBJECT_DECLARE_REF(ei_connection_sync_callback);
|
||||
OBJECT_DECLARE_UNREF(ei_connection_sync_callback);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_sync_callback, context, struct ei*);
|
||||
OBJECT_DECLARE_GETTER(ei_connection_sync_callback, user_data, void*);
|
||||
DEFINE_UNREF_CLEANUP_FUNC(ei_connection_sync_callback);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ eis_connection_destroy(struct eis_connection *connection)
|
|||
struct eis_pingpong *cb;
|
||||
list_for_each_safe(cb, &connection->pending_pingpongs, link) {
|
||||
list_remove(&cb->link);
|
||||
free(eis_pingpong_get_user_data(cb));
|
||||
eis_connection_ping_callback_unref(cb->user_data);
|
||||
eis_pingpong_unref(cb);
|
||||
}
|
||||
}
|
||||
|
|
@ -108,20 +108,53 @@ eis_connection_new(struct eis_client *client)
|
|||
return connection; /* ref owned by caller */
|
||||
}
|
||||
|
||||
struct pingpong_user_data {
|
||||
eis_connection_ping_callback_t cb;
|
||||
void *user_data;
|
||||
};
|
||||
static void
|
||||
eis_connection_ping_callback_destroy(struct eis_connection_ping_callback *callback)
|
||||
{
|
||||
if (callback->destroy)
|
||||
callback->destroy(callback);
|
||||
}
|
||||
|
||||
static
|
||||
OBJECT_IMPLEMENT_CREATE(eis_connection_ping_callback);
|
||||
OBJECT_IMPLEMENT_REF(eis_connection_ping_callback);
|
||||
OBJECT_IMPLEMENT_UNREF(eis_connection_ping_callback);
|
||||
OBJECT_IMPLEMENT_GETTER(eis_connection_ping_callback, user_data, void *);
|
||||
static
|
||||
OBJECT_IMPLEMENT_PARENT(eis_connection_ping_callback, eis_connection);
|
||||
|
||||
struct eis_connection *
|
||||
eis_connection_ping_callback_get_connection(struct eis_connection_ping_callback *callback)
|
||||
{
|
||||
return eis_connection_ping_callback_parent(callback);
|
||||
}
|
||||
|
||||
struct eis_client *
|
||||
eis_connection_ping_callback_get_client(struct eis_connection_ping_callback *callback)
|
||||
{
|
||||
struct eis_connection *connection = eis_connection_ping_callback_get_connection(callback);
|
||||
return eis_connection_get_client(connection);
|
||||
}
|
||||
|
||||
struct eis_connection_ping_callback *
|
||||
eis_connection_ping_callback_new(struct eis_connection *connection,
|
||||
eis_connection_ping_callback_done_t done,
|
||||
eis_connection_ping_callback_destroy_t destroy,
|
||||
void *user_data)
|
||||
{
|
||||
struct eis_connection_ping_callback *callback = eis_connection_ping_callback_create(&connection->object);
|
||||
callback->done = done;
|
||||
callback->destroy = destroy;
|
||||
callback->user_data = user_data;
|
||||
return callback;
|
||||
}
|
||||
|
||||
static void
|
||||
ping_pingpong(struct eis_pingpong *pingpong, void *pingpong_data,
|
||||
uint64_t proto_data)
|
||||
pingpong_callback(struct eis_pingpong *pingpong, void *pingpong_data, uint64_t proto_data)
|
||||
{
|
||||
struct eis_connection *connection = pingpong_data;
|
||||
|
||||
_cleanup_free_ struct pingpong_user_data *data = eis_pingpong_get_user_data(pingpong);
|
||||
if (data->cb)
|
||||
data->cb(connection, data->user_data);
|
||||
_unref_(eis_connection_ping_callback) *data = eis_pingpong_get_user_data(pingpong);
|
||||
if (data->done)
|
||||
data->done(data);
|
||||
|
||||
/* remove from pending callbacks */
|
||||
list_remove(&pingpong->link);
|
||||
|
|
@ -129,21 +162,18 @@ ping_pingpong(struct eis_pingpong *pingpong, void *pingpong_data,
|
|||
}
|
||||
|
||||
void
|
||||
eis_connection_ping(struct eis_connection *connection, eis_connection_ping_callback_t cb,
|
||||
void *user_data)
|
||||
eis_connection_ping(struct eis_connection *connection,
|
||||
struct eis_connection_ping_callback *cb)
|
||||
{
|
||||
struct eis_client *client = eis_connection_get_client(connection);
|
||||
|
||||
/* This is double-wrapped because we only use this for debugging purposes for
|
||||
* now. The actual callback calls sync_callback with our connection,
|
||||
* now. The actual callback calls pingpong_callback with our connection,
|
||||
* then we extract the user_data on the object and call into the
|
||||
* cb supplied to this function.
|
||||
*/
|
||||
struct eis_pingpong *pingpong = eis_pingpong_new(client, ping_pingpong, connection);
|
||||
struct pingpong_user_data *data = xalloc(sizeof *data);
|
||||
data->cb = cb;
|
||||
data->user_data = user_data;
|
||||
eis_pingpong_set_user_data(pingpong, data);
|
||||
struct eis_pingpong *pingpong = eis_pingpong_new(client, pingpong_callback, connection);
|
||||
eis_pingpong_set_user_data(pingpong, eis_connection_ping_callback_ref(cb));
|
||||
list_append(&connection->pending_pingpongs, &pingpong->link);
|
||||
|
||||
eis_connection_event_ping(connection, eis_pingpong_get_id(pingpong),
|
||||
|
|
|
|||
|
|
@ -25,11 +25,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "util-mem.h"
|
||||
#include "util-object.h"
|
||||
#include "brei-shared.h"
|
||||
|
||||
struct eis;
|
||||
struct eis_client;
|
||||
struct eis_connection_ping_callback;
|
||||
|
||||
/* This is a protocol-only object, not exposed in the API */
|
||||
struct eis_connection {
|
||||
|
|
@ -59,7 +61,39 @@ eis_connection_new(struct eis_client *client);
|
|||
typedef void (*eis_connection_ping_callback_t)(struct eis_connection *connection,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Called when the ei_callback.done event is received after
|
||||
* an eis_connection_ping() request.
|
||||
*/
|
||||
typedef void (*eis_connection_ping_callback_done_t)(struct eis_connection_ping_callback *callback);
|
||||
|
||||
/**
|
||||
* Called for each registered callback when the last reference to it is
|
||||
* destroyed. This should be used to clean up user_data, if need be.
|
||||
*
|
||||
* This function is always called, even if disconnected and the done() function is never called.
|
||||
*/
|
||||
typedef void (*eis_connection_ping_callback_destroy_t)(struct eis_connection_ping_callback *callback);
|
||||
|
||||
struct eis_connection_ping_callback {
|
||||
struct object object; /* parent is struct eis */
|
||||
eis_connection_ping_callback_done_t done;
|
||||
eis_connection_ping_callback_destroy_t destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct eis_connection_ping_callback *
|
||||
eis_connection_ping_callback_new(struct eis_connection *connection,
|
||||
eis_connection_ping_callback_done_t done,
|
||||
eis_connection_ping_callback_destroy_t destroy,
|
||||
void *user_data);
|
||||
|
||||
OBJECT_DECLARE_REF(eis_connection_ping_callback);
|
||||
OBJECT_DECLARE_UNREF(eis_connection_ping_callback);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_ping_callback, connection, struct eis_connection *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_ping_callback, client, struct eis_client *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection_ping_callback, user_data, void*);
|
||||
DEFINE_UNREF_CLEANUP_FUNC(eis_connection_ping_callback);
|
||||
|
||||
void
|
||||
eis_connection_ping(struct eis_connection *connection,
|
||||
eis_connection_ping_callback_t callback,
|
||||
void *user_data);
|
||||
eis_connection_ping(struct eis_connection *connection, struct eis_connection_ping_callback *callback);
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ eis_handshake_get_id(struct eis_handshake *setup)
|
|||
}
|
||||
|
||||
static void
|
||||
pong(struct eis_connection *connection, void *user_data)
|
||||
on_pong(struct eis_connection_ping_callback *callback)
|
||||
{
|
||||
struct eis_client *client = eis_connection_get_client(connection);
|
||||
struct eis_client *client = eis_connection_ping_callback_get_client(callback);
|
||||
eis_queue_connect_event(client);
|
||||
}
|
||||
|
||||
|
|
@ -152,9 +152,13 @@ client_msg_finish(struct eis_handshake *setup)
|
|||
setup->client_versions.ei_device == 0) {
|
||||
eis_client_disconnect(client);
|
||||
} else {
|
||||
_unref_(eis_connection_ping_callback) *cb = eis_connection_ping_callback_new(client->connection,
|
||||
on_pong,
|
||||
NULL,
|
||||
NULL);
|
||||
/* Force a ping/pong. This isn't necessary but it doesn't hurt much here
|
||||
* and it ensures that any client implementation doesn't have that part missing */
|
||||
eis_connection_ping(client->connection, pong, NULL);
|
||||
eis_connection_ping(client->connection, cb);
|
||||
}
|
||||
|
||||
client->setup = eis_handshake_unref(setup);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue