mirror of git://git.sysmocom.de/ofono
gisi: simplify pending management
Client or server mark their pending objects with the function g_isi_pending_set_owner(). When client or server get destroyed or reset the pending objects are removed with the function g_isi_remove_pending_by_owner(). As a client or server always uses only a particular resource, all the pending objects are conveniently stored into a single list.
This commit is contained in:
parent
fef6de49af
commit
e72e5444af
199
gisi/client.c
199
gisi/client.c
|
@ -32,58 +32,12 @@
|
|||
|
||||
#include "client.h"
|
||||
|
||||
struct pending_data {
|
||||
GIsiClient *client;
|
||||
GIsiNotifyFunc notify;
|
||||
void *data;
|
||||
GDestroyNotify destroy;
|
||||
};
|
||||
|
||||
struct _GIsiClient {
|
||||
GIsiModem *modem;
|
||||
unsigned timeout;
|
||||
uint8_t resource;
|
||||
GSList *pending;
|
||||
};
|
||||
|
||||
static void pending_destroy(gpointer data)
|
||||
{
|
||||
struct pending_data *pd = data;
|
||||
|
||||
if (pd == NULL)
|
||||
return;
|
||||
|
||||
if (pd->destroy != NULL)
|
||||
pd->destroy(pd->data);
|
||||
|
||||
g_free(pd);
|
||||
}
|
||||
|
||||
static void pending_resp_notify(const GIsiMessage *msg, void *data)
|
||||
{
|
||||
struct pending_data *pd = data;
|
||||
|
||||
if (pd == NULL)
|
||||
return;
|
||||
|
||||
pd->client->pending = g_slist_remove(pd->client->pending,
|
||||
g_isi_pending_from_msg(msg));
|
||||
|
||||
if (pd->notify != NULL)
|
||||
pd->notify(msg, pd->data);
|
||||
}
|
||||
|
||||
static void pending_notify(const GIsiMessage *msg, void *data)
|
||||
{
|
||||
struct pending_data *pd = data;
|
||||
|
||||
if (pd == NULL)
|
||||
return;
|
||||
|
||||
if (pd->notify != NULL)
|
||||
pd->notify(msg, pd->data);
|
||||
}
|
||||
|
||||
uint8_t g_isi_client_resource(GIsiClient *client)
|
||||
{
|
||||
return client != NULL ? client->resource : 0;
|
||||
|
@ -112,31 +66,13 @@ GIsiClient *g_isi_client_create(GIsiModem *modem, uint8_t resource)
|
|||
client->timeout = G_ISI_CLIENT_DEFAULT_TIMEOUT;
|
||||
client->resource = resource;
|
||||
client->modem = modem;
|
||||
client->pending = NULL;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
static void foreach_destroy(gpointer value, gpointer user)
|
||||
{
|
||||
GIsiPending *op = value;
|
||||
GIsiClient *client = user;
|
||||
|
||||
if (op == NULL || client == NULL)
|
||||
return;
|
||||
|
||||
client->pending = g_slist_remove(client->pending, op);
|
||||
g_isi_pending_remove(op);
|
||||
}
|
||||
|
||||
void g_isi_client_reset(GIsiClient *client)
|
||||
{
|
||||
if (client == NULL || client->pending == NULL)
|
||||
return;
|
||||
|
||||
g_slist_foreach(client->pending, foreach_destroy, client);
|
||||
g_slist_free(client->pending);
|
||||
client->pending = NULL;
|
||||
g_isi_remove_pending_by_owner(client->modem, client->resource, client);
|
||||
};
|
||||
|
||||
void g_isi_client_destroy(GIsiClient *client)
|
||||
|
@ -156,43 +92,19 @@ void g_isi_client_set_timeout(GIsiClient *client, unsigned timeout)
|
|||
client->timeout = timeout;
|
||||
}
|
||||
|
||||
static struct pending_data *pending_data_create(GIsiClient *client,
|
||||
GIsiNotifyFunc notify,
|
||||
void *data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
|
||||
if (client == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pd = g_try_new0(struct pending_data, 1);
|
||||
if (pd == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pd->client = client;
|
||||
pd->notify = notify;
|
||||
pd->data = data;
|
||||
pd->destroy = destroy;
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_send(GIsiClient *client,
|
||||
const void *__restrict msg, size_t len,
|
||||
GIsiNotifyFunc notify, void *data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
if (client == NULL)
|
||||
return FALSE;
|
||||
GIsiPending *op;
|
||||
|
||||
return g_isi_client_send_with_timeout(client, msg, len,
|
||||
client->timeout,
|
||||
notify, data, destroy);
|
||||
op = g_isi_request_send(client->modem, client->resource, msg, len,
|
||||
client->timeout, notify, data, destroy);
|
||||
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_send_with_timeout(GIsiClient *client,
|
||||
|
@ -201,23 +113,14 @@ gboolean g_isi_client_send_with_timeout(GIsiClient *client,
|
|||
GIsiNotifyFunc notify, void *data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
GIsiPending *op;
|
||||
|
||||
pd = pending_data_create(client, notify, data, destroy);
|
||||
if (pd == NULL)
|
||||
return FALSE;
|
||||
|
||||
op = g_isi_request_send(client->modem, client->resource, buf, len,
|
||||
timeout, pending_resp_notify, pd,
|
||||
pending_destroy);
|
||||
if (op == NULL) {
|
||||
g_free(pd);
|
||||
return FALSE;
|
||||
}
|
||||
timeout, notify, data, destroy);
|
||||
|
||||
client->pending = g_slist_append(client->pending, op);
|
||||
return TRUE;
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_vsend(GIsiClient *client,
|
||||
|
@ -225,12 +128,14 @@ gboolean g_isi_client_vsend(GIsiClient *client,
|
|||
GIsiNotifyFunc notify, void *data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
if (client == NULL)
|
||||
return FALSE;
|
||||
GIsiPending *op;
|
||||
|
||||
return g_isi_client_vsend_with_timeout(client, iov, iovlen,
|
||||
client->timeout,
|
||||
notify, data, destroy);
|
||||
op = g_isi_request_vsend(client->modem, client->resource, iov, iovlen,
|
||||
client->timeout, notify, data, destroy);
|
||||
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_vsend_with_timeout(GIsiClient *client,
|
||||
|
@ -239,85 +144,51 @@ gboolean g_isi_client_vsend_with_timeout(GIsiClient *client,
|
|||
GIsiNotifyFunc notify, void *data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
GIsiPending *op;
|
||||
|
||||
pd = pending_data_create(client, notify, data, destroy);
|
||||
if (pd == NULL)
|
||||
return FALSE;
|
||||
|
||||
op = g_isi_request_vsend(client->modem, client->resource, iov, iovlen,
|
||||
timeout, pending_resp_notify, pd,
|
||||
pending_destroy);
|
||||
if (op == NULL) {
|
||||
g_free(pd);
|
||||
return FALSE;
|
||||
}
|
||||
timeout, notify, data, destroy);
|
||||
|
||||
client->pending = g_slist_append(client->pending, op);
|
||||
return TRUE;
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_ind_subscribe(GIsiClient *client, uint8_t type,
|
||||
GIsiNotifyFunc notify, void *data)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
GIsiPending *op;
|
||||
|
||||
pd = pending_data_create(client, notify, data, NULL);
|
||||
if (pd == NULL)
|
||||
return FALSE;
|
||||
|
||||
op = g_isi_ind_subscribe(client->modem, client->resource, type,
|
||||
pending_notify, pd, pending_destroy);
|
||||
if (op == NULL) {
|
||||
g_free(pd);
|
||||
return FALSE;
|
||||
}
|
||||
notify, data, NULL);
|
||||
|
||||
client->pending = g_slist_append(client->pending, op);
|
||||
return TRUE;
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_ntf_subscribe(GIsiClient *client, uint8_t type,
|
||||
GIsiNotifyFunc notify, void *data)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
GIsiPending *op;
|
||||
|
||||
pd = pending_data_create(client, notify, data, NULL);
|
||||
if (pd == NULL)
|
||||
return FALSE;
|
||||
|
||||
op = g_isi_ntf_subscribe(client->modem, client->resource, type,
|
||||
pending_notify, pd, pending_destroy);
|
||||
if (op == NULL) {
|
||||
g_free(pd);
|
||||
return FALSE;
|
||||
}
|
||||
notify, data, NULL);
|
||||
|
||||
client->pending = g_slist_append(client->pending, op);
|
||||
return TRUE;
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
gboolean g_isi_client_verify(GIsiClient *client, GIsiNotifyFunc notify,
|
||||
void *data, GDestroyNotify destroy)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
GIsiPending *op;
|
||||
|
||||
pd = pending_data_create(client, notify, data, destroy);
|
||||
if (pd == NULL)
|
||||
return FALSE;
|
||||
|
||||
op = g_isi_resource_ping(client->modem, client->resource,
|
||||
pending_resp_notify, pd,
|
||||
pending_destroy);
|
||||
if (op == NULL) {
|
||||
g_free(pd);
|
||||
return FALSE;
|
||||
}
|
||||
notify, data, destroy);
|
||||
|
||||
client->pending = g_slist_append(client->pending, op);
|
||||
return TRUE;
|
||||
g_isi_pending_set_owner(op, client);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
|
63
gisi/modem.c
63
gisi/modem.c
|
@ -73,6 +73,7 @@ struct _GIsiModem {
|
|||
struct _GIsiPending {
|
||||
enum GIsiMessageType type;
|
||||
GIsiServiceMux *service;
|
||||
gpointer owner;
|
||||
guint timeout;
|
||||
GIsiNotifyFunc notify;
|
||||
GDestroyNotify destroy;
|
||||
|
@ -799,6 +800,68 @@ void g_isi_pending_remove(GIsiPending *op)
|
|||
pending_destroy(op, NULL);
|
||||
}
|
||||
|
||||
static void foreach_destroy(GIsiPending *op)
|
||||
{
|
||||
if (op->type == GISI_MESSAGE_TYPE_IND)
|
||||
service_subs_decr(op->service);
|
||||
|
||||
if (op->type == GISI_MESSAGE_TYPE_REQ)
|
||||
service_regs_decr(op->service);
|
||||
|
||||
if (op->type == GISI_MESSAGE_TYPE_RESP && op->notify != NULL) {
|
||||
GIsiMessage msg = {
|
||||
.error = ESHUTDOWN,
|
||||
};
|
||||
|
||||
pending_dispatch(op, &msg);
|
||||
}
|
||||
|
||||
pending_destroy(op, NULL);
|
||||
}
|
||||
|
||||
void g_isi_pending_set_owner(GIsiPending *op, gpointer owner)
|
||||
{
|
||||
if (op == NULL)
|
||||
return;
|
||||
|
||||
op->owner = owner;
|
||||
}
|
||||
|
||||
void g_isi_remove_pending_by_owner(GIsiModem *modem, uint8_t resource,
|
||||
gpointer owner)
|
||||
{
|
||||
GIsiServiceMux *mux;
|
||||
GSList *l;
|
||||
GSList *next;
|
||||
GIsiPending *op;
|
||||
GSList *owned = NULL;
|
||||
|
||||
mux = service_get(modem, resource);
|
||||
if (mux == NULL)
|
||||
return;
|
||||
|
||||
for (l = mux->pending; l != NULL; l = next) {
|
||||
next = l->next;
|
||||
op = l->data;
|
||||
|
||||
if (op->owner != owner)
|
||||
continue;
|
||||
|
||||
mux->pending = g_slist_remove_link(mux->pending, l);
|
||||
|
||||
l->next = owned;
|
||||
owned = l;
|
||||
}
|
||||
|
||||
for (l = owned; l != NULL; l = l->next) {
|
||||
op = l->data;
|
||||
|
||||
foreach_destroy(op);
|
||||
}
|
||||
|
||||
g_slist_free(owned);
|
||||
}
|
||||
|
||||
GIsiPending *g_isi_ntf_subscribe(GIsiModem *modem, uint8_t resource,
|
||||
uint8_t msgid, GIsiNotifyFunc notify,
|
||||
void *data, GDestroyNotify destroy)
|
||||
|
|
|
@ -109,7 +109,10 @@ int g_isi_response_vsend(GIsiModem *modem, const GIsiMessage *req,
|
|||
|
||||
GIsiPending *g_isi_pending_from_msg(const GIsiMessage *msg);
|
||||
|
||||
void g_isi_pending_remove(GIsiPending *operation);
|
||||
void g_isi_pending_remove(GIsiPending *op);
|
||||
void g_isi_pending_set_owner(GIsiPending *op, gpointer owner);
|
||||
void g_isi_remove_pending_by_owner(GIsiModem *modem, uint8_t resource,
|
||||
gpointer owner);
|
||||
|
||||
GIsiPending *g_isi_resource_ping(GIsiModem *modem, uint8_t resource,
|
||||
GIsiNotifyFunc notify, void *data,
|
||||
|
|
|
@ -32,30 +32,12 @@
|
|||
|
||||
#include "server.h"
|
||||
|
||||
struct pending_data {
|
||||
GIsiServer *server;
|
||||
GIsiNotifyFunc notify;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct _GIsiServer {
|
||||
GIsiModem *modem;
|
||||
GIsiVersion version;
|
||||
uint8_t resource;
|
||||
GSList *pending;
|
||||
};
|
||||
|
||||
static void pending_notify(const GIsiMessage *msg, void *data)
|
||||
{
|
||||
struct pending_data *pd = data;
|
||||
|
||||
if (pd == NULL)
|
||||
return;
|
||||
|
||||
if (pd->notify != NULL)
|
||||
pd->notify(msg, pd->data);
|
||||
}
|
||||
|
||||
uint8_t g_isi_server_resource(GIsiServer *server)
|
||||
{
|
||||
return server != NULL ? server->resource : 0;
|
||||
|
@ -87,30 +69,17 @@ GIsiServer *g_isi_server_create(GIsiModem *modem, uint8_t resource,
|
|||
|
||||
server->resource = resource;
|
||||
server->modem = modem;
|
||||
server->pending = NULL;
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
static void foreach_destroy(gpointer value, gpointer user)
|
||||
{
|
||||
GIsiPending *op = value;
|
||||
GIsiServer *server = user;
|
||||
|
||||
if (op == NULL || server == NULL)
|
||||
return;
|
||||
|
||||
server->pending = g_slist_remove(server->pending, op);
|
||||
g_isi_pending_remove(op);
|
||||
}
|
||||
|
||||
void g_isi_server_destroy(GIsiServer *server)
|
||||
{
|
||||
if (server == NULL)
|
||||
return;
|
||||
|
||||
g_slist_foreach(server->pending, foreach_destroy, server);
|
||||
g_slist_free(server->pending);
|
||||
g_isi_remove_pending_by_owner(server->modem, server->resource, server);
|
||||
|
||||
g_free(server);
|
||||
}
|
||||
|
||||
|
@ -132,47 +101,15 @@ int g_isi_server_vsend(GIsiServer *server, const GIsiMessage *req,
|
|||
return g_isi_response_vsend(server->modem, req, iov, iovlen);
|
||||
}
|
||||
|
||||
static struct pending_data *pending_data_create(GIsiServer *server,
|
||||
GIsiNotifyFunc notify,
|
||||
void *data)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
|
||||
if (server == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pd = g_try_new0(struct pending_data, 1);
|
||||
if (pd == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pd->server = server;
|
||||
pd->notify = notify;
|
||||
pd->data = data;
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
GIsiPending *g_isi_server_handle(GIsiServer *server, uint8_t type,
|
||||
GIsiNotifyFunc notify, void *data)
|
||||
{
|
||||
struct pending_data *pd;
|
||||
GIsiPending *op;
|
||||
|
||||
pd = pending_data_create(server, notify, data);
|
||||
if (pd == NULL)
|
||||
return NULL;
|
||||
|
||||
op = g_isi_service_bind(server->modem, server->resource, type,
|
||||
pending_notify, pd, g_free);
|
||||
if (op == NULL) {
|
||||
g_free(pd);
|
||||
return NULL;
|
||||
}
|
||||
notify, data, NULL);
|
||||
|
||||
g_isi_pending_set_owner(op, server);
|
||||
|
||||
server->pending = g_slist_append(server->pending, op);
|
||||
return op;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue