Add reference counter to mcap_mdl

This commit is contained in:
Santiago Carot-Nemesio 2010-11-12 13:55:33 +01:00 committed by Johan Hedberg
parent 0ddd53f98b
commit bcfaa65382
4 changed files with 66 additions and 41 deletions

View File

@ -105,6 +105,7 @@ static void free_health_channel(struct hdp_channel *chan)
if (chan->mdep == HDP_MDEP_ECHO)
free_echo_data(chan->edata);
mcap_mdl_unref(chan->mdl);
hdp_application_unref(chan->app);
health_device_unref(chan->dev);
g_free(chan->path);
@ -763,7 +764,7 @@ static struct hdp_channel *create_channel(struct hdp_device *dev,
hdp_chann = g_new0(struct hdp_channel, 1);
hdp_chann->config = config;
hdp_chann->dev = health_device_ref(dev);
hdp_chann->mdl = mdl;
hdp_chann->mdl = mcap_mdl_ref(mdl);
hdp_chann->mdlid = mdlid;
hdp_chann->app = hdp_application_ref(app);
@ -920,7 +921,7 @@ static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
return;
chan = dev->ndc;
chan->mdl = mdl;
chan->mdl = mcap_mdl_ref(mdl);
if (!g_slist_find(dev->channels, chan))
dev->channels = g_slist_prepend(dev->channels,
@ -1004,7 +1005,7 @@ static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
if (!dev->ndc)
return;
dev->ndc->mdl = mdl;
dev->ndc->mdl = mcap_mdl_ref(mdl);
if (!g_slist_find(dev->channels, dev->ndc))
dev->channels = g_slist_prepend(dev->channels,
@ -1735,9 +1736,11 @@ fail:
/* Send abort request because remote side is now in PENDING */
/* state. Then we have to delete it because we couldn't */
/* register the HealthChannel interface */
if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mdl, NULL, &gerr)) {
if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl), NULL,
&gerr)) {
error("%s", gerr->message);
g_error_free(gerr);
mcap_mdl_unref(mdl);
}
}

View File

@ -263,14 +263,20 @@ static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
return 1;
}
static void free_mcl_priv_data(struct mcap_mcl *mcl)
static void free_mcap_mdl_op(struct mcap_mdl_op_cb *op)
{
struct mcap_mdl_op_cb *op = mcl->priv_data;
if (op->destroy)
op->destroy(op->user_data);
g_free(mcl->priv_data);
if (op->mdl)
mcap_mdl_unref(op->mdl);
g_free(op);
}
static void free_mcl_priv_data(struct mcap_mcl *mcl)
{
free_mcap_mdl_op(mcl->priv_data);
mcl->priv_data = NULL;
}
@ -290,7 +296,7 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
mdl = l->data;
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
free_mdl(mdl);
mcap_mdl_unref(mdl);
update_mcl_state(mcl);
con->cb.op_conf(NULL, 0, err, con->user_data);
break;
@ -484,7 +490,7 @@ gboolean mcap_create_mdl(struct mcap_mcl *mcl,
mdl->state = MDL_WAITING;
con = g_new0(struct mcap_mdl_op_cb, 1);
con->mdl = mdl;
con->mdl = mcap_mdl_ref(mdl);
con->cb.op_conf = connect_cb;
con->destroy = destroy;
con->user_data = user_data;
@ -492,7 +498,7 @@ gboolean mcap_create_mdl(struct mcap_mcl *mcl,
cmd = create_mdl_req(id, mdepid, conf);
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req),
err)) {
free_mdl(mdl);
mcap_mdl_unref(con->mdl);
g_free(con);
g_free(cmd);
return FALSE;
@ -501,7 +507,8 @@ gboolean mcap_create_mdl(struct mcap_mcl *mcl,
mcl->state = MCL_ACTIVE;
mcl->priv_data = con;
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
compare_mdl);
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
mcl);
return TRUE;
@ -533,7 +540,7 @@ gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl,
mdl->state = MDL_WAITING;
con->mdl = mdl;
con->mdl = mcap_mdl_ref(mdl);
con->cb.op = reconnect_cb;
con->destroy = destroy;
con->user_data = user_data;
@ -630,12 +637,13 @@ gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
mdl->state = MDL_DELETING;
con = g_new0(struct mcap_mdl_op_cb, 1);
con->mdl = mdl;
con->mdl = mcap_mdl_ref(mdl);
con->cb.notify = delete_cb;
con->destroy = destroy;
con->user_data = user_data;
if (!send_delete_req(mcl, con, mdl->mdlid, err)) {
mcap_mdl_unref(con->mdl);
g_free(con);
return FALSE;
}
@ -666,7 +674,7 @@ gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
return FALSE;
}
con->mdl = mdl;
con->mdl = mcap_mdl_ref(mdl);
con->cb.notify = abort_cb;
con->destroy = destroy;
con->user_data = user_data;
@ -742,7 +750,7 @@ static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
if (save)
return;
g_slist_foreach(mcl->mdls, (GFunc) free_mdl, NULL);
g_slist_foreach(mcl->mdls, (GFunc) mcap_mdl_unref, NULL);
g_slist_free(mcl->mdls);
mcl->mdls = NULL;
}
@ -952,7 +960,7 @@ static void mcap_del_mdl(gpointer elem, gpointer user_data)
if (notify)
mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
free_mdl(mdl);
mcap_mdl_unref(mdl);
}
static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
@ -1041,7 +1049,8 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
mdl = g_new0(struct mcap_mdl, 1);
mdl->mcl = mcap_mcl_ref(mcl);
mdl->mdlid = mdl_id;
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
compare_mdl);
} else if (mdl->state == MDL_CONNECTED) {
/* MCAP specification says that we should close the MCL if
* it is open when we receive a MD_CREATE_MDL_REQ */
@ -1351,7 +1360,7 @@ static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
fail:
connect_cb(NULL, 0, gerr, user_data);
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
free_mdl(mdl);
mcap_mdl_unref(mdl);
g_error_free(gerr);
update_mcl_state(mcl);
return close;
@ -1387,7 +1396,7 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
/* Remove cached mdlid */
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
free_mdl(mdl);
mcap_mdl_unref(mdl);
return close;
}
@ -1414,7 +1423,7 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) {
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
free_mdl(mdl);
mcap_mdl_unref(mdl);
}
if (gerr)
@ -1447,7 +1456,7 @@ static void check_mdl_del_err(struct mcap_mdl *mdl, mcap_rsp *rsp)
/* MDL does not exist in remote side, we can delete it */
mdl->mcl->mdls = g_slist_remove(mdl->mcl->mdls, mdl);
free_mdl(mdl);
mcap_mdl_unref(mdl);
}
static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
@ -1497,18 +1506,14 @@ static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
static void post_process_rsp(struct mcap_mcl *mcl, struct mcap_mdl_op_cb *op)
{
if (op->destroy)
op->destroy(op->user_data);
if (mcl->priv_data != op) {
/* Queued MCAP request in some callback. */
/* We should not delete the mcl private data */
g_free(op);
free_mcap_mdl_op(op);
} else {
/* This is not a queued request. It's safe */
/* delete the mcl private data here. */
g_free(mcl->priv_data);
mcl->priv_data = NULL;
free_mcl_priv_data(mcl);
}
}
@ -1641,16 +1646,6 @@ static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
cb(mdl, conn_err, user_data);
}
static void mdl_io_destroy(gpointer data)
{
struct mcap_mdl_op_cb *con = data;
if (con->destroy)
con->destroy(con->user_data);
g_free(con);
}
gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode,
uint16_t dcpsm,
mcap_mdl_operation_cb connect_cb,
@ -1673,13 +1668,13 @@ gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode,
}
con = g_new0(struct mcap_mdl_op_cb, 1);
con->mdl = mdl;
con->mdl = mcap_mdl_ref(mdl);
con->cb.op = connect_cb;
con->destroy = destroy;
con->user_data = user_data;
mdl->dc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mdl_cb, con,
mdl_io_destroy, err,
(GDestroyNotify) free_mcap_mdl_op, err,
BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->ms->src,
BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr,
BT_IO_OPT_PSM, dcpsm,
@ -1690,6 +1685,7 @@ gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode,
if (!mdl->dc) {
DBG("MDL Connection error");
mdl->state = MDL_CLOSED;
mcap_mdl_unref(con->mdl);
g_free(con);
return FALSE;
}
@ -2167,3 +2163,24 @@ gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode,
return bt_io_set(mi->dcio, BT_IO_L2CAP, err, BT_IO_OPT_MODE, mode,
BT_IO_OPT_INVALID);
}
struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl)
{
mdl->ref++;
DBG("mcap_mdl_ref(%p): ref=%d", mdl, mdl->ref);
return mdl;
}
void mcap_mdl_unref(struct mcap_mdl *mdl)
{
mdl->ref--;
DBG("mcap_mdl_unref(%p): ref=%d", mdl, mdl->ref);
if (mdl->ref > 0)
return;
free_mdl(mdl);
}

View File

@ -84,6 +84,7 @@ struct mcap_instance {
};
struct mcap_csp;
struct mcap_mdl_op_cb;
struct mcap_mcl {
struct mcap_instance *ms; /* MCAP instance where this MCL belongs */
@ -94,7 +95,7 @@ struct mcap_mcl {
MCLState state; /* Current MCL State */
MCLRole role; /* Initiator or acceptor of this MCL */
MCAPCtrl req; /* Request control flag */
void *priv_data; /* Temporal data to manage responses */
struct mcap_mdl_op_cb *priv_data; /* Temporal data to manage responses */
struct mcap_mdl_cb *cb; /* MDL callbacks */
guint tid; /* Timer id for waiting for a response */
uint8_t *lcmd; /* Last command sent */
@ -118,6 +119,7 @@ struct mcap_mdl {
uint16_t mdlid; /* MDL id */
uint8_t mdep_id; /* MCAP Data End Point */
MDLState state; /* MDL state */
gint ref; /* References counter */
};
struct sync_info_ind_data {

View File

@ -155,6 +155,9 @@ gboolean mcap_mdl_abort(struct mcap_mdl *mdl,
int mcap_mdl_get_fd(struct mcap_mdl *mdl);
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl);
struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl);
void mcap_mdl_unref(struct mcap_mdl *mdl);
/* MCL operations */
gboolean mcap_create_mcl(struct mcap_instance *ms,