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:
Pekka Pessi 2011-01-18 23:27:08 +02:00 committed by Aki Niemi
parent fef6de49af
commit e72e5444af
4 changed files with 107 additions and 233 deletions

View File

@ -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;
}

View File

@ -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)

View File

@ -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,

View File

@ -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;
}