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" #include "client.h"
struct pending_data {
GIsiClient *client;
GIsiNotifyFunc notify;
void *data;
GDestroyNotify destroy;
};
struct _GIsiClient { struct _GIsiClient {
GIsiModem *modem; GIsiModem *modem;
unsigned timeout; unsigned timeout;
uint8_t resource; 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) uint8_t g_isi_client_resource(GIsiClient *client)
{ {
return client != NULL ? client->resource : 0; 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->timeout = G_ISI_CLIENT_DEFAULT_TIMEOUT;
client->resource = resource; client->resource = resource;
client->modem = modem; client->modem = modem;
client->pending = NULL;
return client; 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) void g_isi_client_reset(GIsiClient *client)
{ {
if (client == NULL || client->pending == NULL) g_isi_remove_pending_by_owner(client->modem, client->resource, client);
return;
g_slist_foreach(client->pending, foreach_destroy, client);
g_slist_free(client->pending);
client->pending = NULL;
}; };
void g_isi_client_destroy(GIsiClient *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; 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, gboolean g_isi_client_send(GIsiClient *client,
const void *__restrict msg, size_t len, const void *__restrict msg, size_t len,
GIsiNotifyFunc notify, void *data, GIsiNotifyFunc notify, void *data,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
if (client == NULL) GIsiPending *op;
return FALSE;
return g_isi_client_send_with_timeout(client, msg, len, op = g_isi_request_send(client->modem, client->resource, msg, len,
client->timeout, client->timeout, notify, data, destroy);
notify, data, destroy);
g_isi_pending_set_owner(op, client);
return op != NULL;
} }
gboolean g_isi_client_send_with_timeout(GIsiClient *client, 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, GIsiNotifyFunc notify, void *data,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
struct pending_data *pd;
GIsiPending *op; 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, op = g_isi_request_send(client->modem, client->resource, buf, len,
timeout, pending_resp_notify, pd, timeout, notify, data, destroy);
pending_destroy);
if (op == NULL) {
g_free(pd);
return FALSE;
}
client->pending = g_slist_append(client->pending, op); g_isi_pending_set_owner(op, client);
return TRUE;
return op != NULL;
} }
gboolean g_isi_client_vsend(GIsiClient *client, gboolean g_isi_client_vsend(GIsiClient *client,
@ -225,12 +128,14 @@ gboolean g_isi_client_vsend(GIsiClient *client,
GIsiNotifyFunc notify, void *data, GIsiNotifyFunc notify, void *data,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
if (client == NULL) GIsiPending *op;
return FALSE;
return g_isi_client_vsend_with_timeout(client, iov, iovlen, op = g_isi_request_vsend(client->modem, client->resource, iov, iovlen,
client->timeout, client->timeout, notify, data, destroy);
notify, data, destroy);
g_isi_pending_set_owner(op, client);
return op != NULL;
} }
gboolean g_isi_client_vsend_with_timeout(GIsiClient *client, 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, GIsiNotifyFunc notify, void *data,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
struct pending_data *pd;
GIsiPending *op; 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, op = g_isi_request_vsend(client->modem, client->resource, iov, iovlen,
timeout, pending_resp_notify, pd, timeout, notify, data, destroy);
pending_destroy);
if (op == NULL) {
g_free(pd);
return FALSE;
}
client->pending = g_slist_append(client->pending, op); g_isi_pending_set_owner(op, client);
return TRUE;
return op != NULL;
} }
gboolean g_isi_client_ind_subscribe(GIsiClient *client, uint8_t type, gboolean g_isi_client_ind_subscribe(GIsiClient *client, uint8_t type,
GIsiNotifyFunc notify, void *data) GIsiNotifyFunc notify, void *data)
{ {
struct pending_data *pd;
GIsiPending *op; 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, op = g_isi_ind_subscribe(client->modem, client->resource, type,
pending_notify, pd, pending_destroy); notify, data, NULL);
if (op == NULL) {
g_free(pd);
return FALSE;
}
client->pending = g_slist_append(client->pending, op); g_isi_pending_set_owner(op, client);
return TRUE;
return op != NULL;
} }
gboolean g_isi_client_ntf_subscribe(GIsiClient *client, uint8_t type, gboolean g_isi_client_ntf_subscribe(GIsiClient *client, uint8_t type,
GIsiNotifyFunc notify, void *data) GIsiNotifyFunc notify, void *data)
{ {
struct pending_data *pd;
GIsiPending *op; 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, op = g_isi_ntf_subscribe(client->modem, client->resource, type,
pending_notify, pd, pending_destroy); notify, data, NULL);
if (op == NULL) {
g_free(pd);
return FALSE;
}
client->pending = g_slist_append(client->pending, op); g_isi_pending_set_owner(op, client);
return TRUE;
return op != NULL;
} }
gboolean g_isi_client_verify(GIsiClient *client, GIsiNotifyFunc notify, gboolean g_isi_client_verify(GIsiClient *client, GIsiNotifyFunc notify,
void *data, GDestroyNotify destroy) void *data, GDestroyNotify destroy)
{ {
struct pending_data *pd;
GIsiPending *op; GIsiPending *op;
pd = pending_data_create(client, notify, data, destroy);
if (pd == NULL)
return FALSE;
op = g_isi_resource_ping(client->modem, client->resource, op = g_isi_resource_ping(client->modem, client->resource,
pending_resp_notify, pd, notify, data, destroy);
pending_destroy);
if (op == NULL) {
g_free(pd);
return FALSE;
}
client->pending = g_slist_append(client->pending, op); g_isi_pending_set_owner(op, client);
return TRUE;
return op != NULL;
} }

View File

@ -73,6 +73,7 @@ struct _GIsiModem {
struct _GIsiPending { struct _GIsiPending {
enum GIsiMessageType type; enum GIsiMessageType type;
GIsiServiceMux *service; GIsiServiceMux *service;
gpointer owner;
guint timeout; guint timeout;
GIsiNotifyFunc notify; GIsiNotifyFunc notify;
GDestroyNotify destroy; GDestroyNotify destroy;
@ -799,6 +800,68 @@ void g_isi_pending_remove(GIsiPending *op)
pending_destroy(op, NULL); 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, GIsiPending *g_isi_ntf_subscribe(GIsiModem *modem, uint8_t resource,
uint8_t msgid, GIsiNotifyFunc notify, uint8_t msgid, GIsiNotifyFunc notify,
void *data, GDestroyNotify destroy) 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); 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, GIsiPending *g_isi_resource_ping(GIsiModem *modem, uint8_t resource,
GIsiNotifyFunc notify, void *data, GIsiNotifyFunc notify, void *data,

View File

@ -32,30 +32,12 @@
#include "server.h" #include "server.h"
struct pending_data {
GIsiServer *server;
GIsiNotifyFunc notify;
void *data;
};
struct _GIsiServer { struct _GIsiServer {
GIsiModem *modem; GIsiModem *modem;
GIsiVersion version; GIsiVersion version;
uint8_t resource; 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) uint8_t g_isi_server_resource(GIsiServer *server)
{ {
return server != NULL ? server->resource : 0; return server != NULL ? server->resource : 0;
@ -87,30 +69,17 @@ GIsiServer *g_isi_server_create(GIsiModem *modem, uint8_t resource,
server->resource = resource; server->resource = resource;
server->modem = modem; server->modem = modem;
server->pending = NULL;
return server; 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) void g_isi_server_destroy(GIsiServer *server)
{ {
if (server == NULL) if (server == NULL)
return; return;
g_slist_foreach(server->pending, foreach_destroy, server); g_isi_remove_pending_by_owner(server->modem, server->resource, server);
g_slist_free(server->pending);
g_free(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); 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, GIsiPending *g_isi_server_handle(GIsiServer *server, uint8_t type,
GIsiNotifyFunc notify, void *data) GIsiNotifyFunc notify, void *data)
{ {
struct pending_data *pd;
GIsiPending *op; GIsiPending *op;
pd = pending_data_create(server, notify, data);
if (pd == NULL)
return NULL;
op = g_isi_service_bind(server->modem, server->resource, type, op = g_isi_service_bind(server->modem, server->resource, type,
pending_notify, pd, g_free); notify, data, NULL);
if (op == NULL) {
g_free(pd); g_isi_pending_set_owner(op, server);
return NULL;
}
server->pending = g_slist_append(server->pending, op);
return op; return op;
} }