Re: [PATCH 1/1] obexd: Queue session commands

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Christian,

On Fri, May 24, 2013 at 5:39 AM, Christian Fetzer
<christian.fetzer@xxxxxxxxxxxxxxxx> wrote:
> From: Christian Fetzer <christian.fetzer@xxxxxxxxxxxx>
>
> So far only transfers are queued in OBEX sessions. Commands like SetPath
> are not queued and the commands will simply fail when a different
> operation or transfer is ongoing. This patch removes this limitation and
> queues commands as well.
>
> Currently, the MAP client is directly affected by this limitation.
> An immediate call to SetPath after the MAP connection has been established
> reliably fails, because MNS is being connected in the background in parallel.
> ---
>  obexd/client/session.c | 271 ++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 190 insertions(+), 81 deletions(-)
>
> diff --git a/obexd/client/session.c b/obexd/client/session.c
> index f1bdf18..bffc015 100644
> --- a/obexd/client/session.c
> +++ b/obexd/client/session.c
> @@ -65,10 +65,18 @@ struct callback_data {
>         void *data;
>  };
>
> +struct pending_request;
> +typedef int (*session_process_cb) (struct pending_request *pr, GError **err);
> +
> +typedef void (*process_free_cb)(void *process_data);

Call it pending_destroy and there should be only one data here.

>  struct pending_request {
>         guint id;
>         guint req_id;
>         struct obc_session *session;
> +       session_process_cb process;
> +       void *process_data;

No need to create another data parameter if it is a void * you can
always stuff a struct that carries another data if needed. You should
probably stuff the func and the transfer in a specialized request
which is the passed as data to pending_request_new., the process
callback should know how to treat its data.

> +       process_free_cb process_free;
>         struct obc_transfer *transfer;
>         session_callback_t func;
>         void *data;
> @@ -81,6 +89,11 @@ struct setpath_data {
>         void *user_data;
>  };
>
> +struct file_data {
> +       char *srcname;
> +       char *destname;
> +};
> +
>  struct obc_session {
>         guint id;
>         int refcount;
> @@ -140,6 +153,9 @@ static void session_unregistered(struct obc_session *session)
>  }
>
>  static struct pending_request *pending_request_new(struct obc_session *session,
> +                                               session_process_cb process,
> +                                               void *process_data,
> +                                               process_free_cb process_free,
>                                                 struct obc_transfer *transfer,
>                                                 session_callback_t func,
>                                                 void *data)
> @@ -150,6 +166,9 @@ static struct pending_request *pending_request_new(struct obc_session *session,
>         p = g_new0(struct pending_request, 1);
>         p->id = ++id;
>         p->session = obc_session_ref(session);
> +       p->process = process;
> +       p->process_data = process_data;
> +       p->process_free = process_free;
>         p->transfer = transfer;
>         p->func = func;
>         p->data = data;
> @@ -159,6 +178,9 @@ static struct pending_request *pending_request_new(struct obc_session *session,
>
>  static void pending_request_free(struct pending_request *p)
>  {
> +       if (p->process_free && p->process_data)
> +               p->process_free(p->process_data);
> +
>         if (p->transfer)
>                 obc_transfer_unregister(p->transfer);
>
> @@ -168,6 +190,23 @@ static void pending_request_free(struct pending_request *p)
>         g_free(p);
>  }
>
> +static void setpath_data_free(void *process_data)
> +{
> +       struct setpath_data *data = process_data;
> +
> +       g_strfreev(data->remaining);
> +       g_free(data);
> +}
> +
> +static void file_data_free(void *process_data)
> +{
> +       struct file_data *data = process_data;
> +
> +       g_free(data->srcname);
> +       g_free(data->destname);
> +       g_free(data);
> +}
> +
>  static void session_free(struct obc_session *session)
>  {
>         DBG("%p", session);
> @@ -656,6 +695,15 @@ static gboolean session_queue_complete(gpointer data)
>         return FALSE;
>  }
>
> +static int session_process_transfer(struct pending_request *p, GError **err)
> +{
> +       if (obc_transfer_start(p->transfer, p->session->obex, err)) {
> +               p->session->p = p;
> +               return 0;
> +       }
> +       return -1;
> +}
> +
>  guint obc_session_queue(struct obc_session *session,
>                                 struct obc_transfer *transfer,
>                                 session_callback_t func, void *user_data,
> @@ -678,7 +726,8 @@ guint obc_session_queue(struct obc_session *session,
>
>         obc_transfer_set_callback(transfer, transfer_complete, session);
>
> -       p = pending_request_new(session, transfer, func, user_data);
> +       p = pending_request_new(session, session_process_transfer, NULL, NULL,
> +                                               transfer, func, user_data);
>         g_queue_push_tail(session->queue, p);
>
>         if (session->queue_complete_id == 0)
> @@ -703,12 +752,8 @@ static void session_process_queue(struct obc_session *session)
>         while ((p = g_queue_pop_head(session->queue))) {
>                 GError *gerr = NULL;
>
> -               DBG("Transfer(%p) started", p->transfer);
> -
> -               if (obc_transfer_start(p->transfer, session->obex, &gerr)) {
> -                       session->p = p;
> +               if (p->process(p, &gerr) == 0)
>                         break;
> -               }
>
>                 if (p->func)
>                         p->func(session, p->transfer, gerr, p->data);
> @@ -864,9 +909,6 @@ static void setpath_complete(struct obc_session *session,
>         if (data->func)
>                 data->func(session, NULL, err, data->user_data);
>
> -       g_strfreev(data->remaining);
> -       g_free(data);
> -
>         if (session->p == p)
>                 session->p = NULL;
>
> @@ -918,13 +960,35 @@ static void setpath_cb(GObex *obex, GError *err, GObexPacket *rsp,
>         }
>  }
>
> +static int session_process_setpath(struct pending_request *p, GError **err)
> +{
> +       struct setpath_data *req = p->process_data;
> +       const char *first = "";
> +
> +       /* Relative path */
> +       if (req->remaining[0][0] != '/')
> +               first = req->remaining[req->index];
> +       req->index++;
> +
> +       p->req_id = g_obex_setpath(p->session->obex, first, setpath_cb, p, err);
> +       if (*err != NULL)
> +               goto fail;
> +
> +       p->session->p = p;
> +
> +       return 0;
> +
> +fail:
> +       pending_request_free(p);
> +       return (*err)->code;
> +}
> +
>  guint obc_session_setpath(struct obc_session *session, const char *path,
>                                 session_callback_t func, void *user_data,
>                                 GError **err)
>  {
>         struct setpath_data *data;
>         struct pending_request *p;
> -       const char *first = "";
>
>         if (session->obex == NULL) {
>                 g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
> @@ -932,38 +996,20 @@ guint obc_session_setpath(struct obc_session *session, const char *path,
>                 return 0;
>         }
>
> -       if (session->p != NULL) {
> -               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_BUSY,
> -                                                       "Session busy");
> -               return 0;
> -       }
> -
>         data = g_new0(struct setpath_data, 1);
>         data->func = func;
>         data->user_data = user_data;
>         data->remaining = g_strsplit(strlen(path) ? path : "/", "/", 0);
>
> -       p = pending_request_new(session, NULL, setpath_complete, data);
> -
> -       /* Relative path */
> -       if (path[0] != '/')
> -               first = data->remaining[data->index];
> -
> -       data->index++;
> -
> -       p->req_id = g_obex_setpath(session->obex, first, setpath_cb, p, err);
> -       if (*err != NULL)
> -               goto fail;
> +       p = pending_request_new(session, session_process_setpath, data,
> +                       setpath_data_free, NULL, setpath_complete, data);

It just reinforce the idea that just one data is required as you have
data twice here.

> +       g_queue_push_tail(session->queue, p);
>
> -       session->p = p;
> +       if (session->queue_complete_id == 0)
> +               session->queue_complete_id = g_idle_add(
> +                                       session_queue_complete, session);
>
>         return p->id;
> -
> -fail:
> -       g_strfreev(data->remaining);
> -       g_free(data);
> -       pending_request_free(p);
> -       return 0;
>  }
>
>  static void async_cb(GObex *obex, GError *err, GObexPacket *rsp,
> @@ -1000,10 +1046,29 @@ done:
>         session_process_queue(session);
>  }
>
> +static int session_process_mkdir(struct pending_request *p, GError **err)
> +{
> +       struct file_data *req = p->process_data;
> +
> +       p->req_id = g_obex_mkdir(p->session->obex, req->srcname, async_cb, p,
> +                                                                       err);
> +       if (*err != NULL)
> +               goto fail;
> +
> +       p->session->p = p;
> +
> +       return 0;
> +
> +fail:
> +       pending_request_free(p);
> +       return (*err)->code;
> +}
> +
>  guint obc_session_mkdir(struct obc_session *session, const char *folder,
>                                 session_callback_t func, void *user_data,
>                                 GError **err)
>  {
> +       struct file_data *data;
>         struct pending_request *p;
>
>         if (session->obex == NULL) {
> @@ -1012,28 +1077,43 @@ guint obc_session_mkdir(struct obc_session *session, const char *folder,
>                 return 0;
>         }
>
> -       if (session->p != NULL) {
> -               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_BUSY, "Session busy");
> -               return 0;
> -       }
> -
> +       data = g_new0(struct file_data, 1);
> +       data->srcname = g_strdup(folder);
>
> -       p = pending_request_new(session, NULL, func, user_data);
> +       p = pending_request_new(session, session_process_mkdir, data,
> +                                       file_data_free, NULL, func, user_data);
> +       g_queue_push_tail(session->queue, p);
>
> -       p->req_id = g_obex_mkdir(session->obex, folder, async_cb, p, err);
> -       if (*err != NULL) {
> -               pending_request_free(p);
> -               return 0;
> -       }
> +       if (session->queue_complete_id == 0)
> +               session->queue_complete_id = g_idle_add(
> +                                       session_queue_complete, session);
>
> -       session->p = p;
>         return p->id;
>  }
>
> +static int session_process_copy(struct pending_request *p, GError **err)
> +{
> +       struct file_data *req = p->process_data;
> +
> +       p->req_id = g_obex_copy(p->session->obex, req->srcname, req->destname,
> +                                                       async_cb, p, err);
> +       if (*err != NULL)
> +               goto fail;
> +
> +       p->session->p = p;
> +
> +       return 0;
> +
> +fail:
> +       pending_request_free(p);
> +       return (*err)->code;
> +}
> +
>  guint obc_session_copy(struct obc_session *session, const char *srcname,
>                                 const char *destname, session_callback_t func,
>                                 void *user_data, GError **err)
>  {
> +       struct file_data *data;
>         struct pending_request *p;
>
>         if (session->obex == NULL) {
> @@ -1042,28 +1122,44 @@ guint obc_session_copy(struct obc_session *session, const char *srcname,
>                 return 0;
>         }
>
> -       if (session->p != NULL) {
> -               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_BUSY, "Session busy");
> -               return 0;
> -       }
> +       data = g_new0(struct file_data, 1);
> +       data->srcname = g_strdup(srcname);
> +       data->destname = g_strdup(destname);
>
> -       p = pending_request_new(session, NULL, func, user_data);
> +       p = pending_request_new(session, session_process_copy, data,
> +                                       file_data_free, NULL, func, user_data);
> +       g_queue_push_tail(session->queue, p);
>
> -       p->req_id = g_obex_copy(session->obex, srcname, destname, async_cb, p,
> -                                                                       err);
> -       if (*err != NULL) {
> -               pending_request_free(p);
> -               return 0;
> -       }
> +       if (session->queue_complete_id == 0)
> +               session->queue_complete_id = g_idle_add(
> +                                       session_queue_complete, session);
>
> -       session->p = p;
>         return p->id;
>  }
>
> +static int session_process_move(struct pending_request *p, GError **err)
> +{
> +       struct file_data *req = p->process_data;
> +
> +       p->req_id = g_obex_move(p->session->obex, req->srcname, req->destname,
> +                                                       async_cb, p, err);
> +       if (*err != NULL)
> +               goto fail;
> +
> +       p->session->p = p;
> +
> +       return 0;
> +
> +fail:
> +       pending_request_free(p);
> +       return (*err)->code;
> +}
> +
>  guint obc_session_move(struct obc_session *session, const char *srcname,
>                                 const char *destname, session_callback_t func,
>                                 void *user_data, GError **err)
>  {
> +       struct file_data *data;
>         struct pending_request *p;
>
>         if (session->obex == NULL) {
> @@ -1072,28 +1168,44 @@ guint obc_session_move(struct obc_session *session, const char *srcname,
>                 return 0;
>         }
>
> -       if (session->p != NULL) {
> -               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_BUSY, "Session busy");
> -               return 0;
> -       }
> +       data = g_new0(struct file_data, 1);
> +       data->srcname = g_strdup(srcname);
> +       data->destname = g_strdup(destname);
>
> -       p = pending_request_new(session, NULL, func, user_data);
> +       p = pending_request_new(session, session_process_move, data,
> +                                       file_data_free, NULL, func, user_data);
> +       g_queue_push_tail(session->queue, p);
>
> -       p->req_id = g_obex_move(session->obex, srcname, destname, async_cb, p,
> -                                                                       err);
> -       if (*err != NULL) {
> -               pending_request_free(p);
> -               return 0;
> -       }
> +       if (session->queue_complete_id == 0)
> +               session->queue_complete_id = g_idle_add(
> +                                       session_queue_complete, session);
>
> -       session->p = p;
>         return p->id;
>  }
>
> +static int session_process_delete(struct pending_request *p, GError **err)
> +{
> +       struct file_data *req = p->process_data;
> +
> +       p->req_id = g_obex_delete(p->session->obex, req->srcname, async_cb, p,
> +                                                                       err);
> +       if (*err != NULL)
> +               goto fail;
> +
> +       p->session->p = p;
> +
> +       return 0;
> +
> +fail:
> +       pending_request_free(p);
> +       return (*err)->code;
> +}
> +
>  guint obc_session_delete(struct obc_session *session, const char *file,
>                                 session_callback_t func, void *user_data,
>                                 GError **err)
>  {
> +       struct file_data *data;
>         struct pending_request *p;
>
>         if (session->obex == NULL) {
> @@ -1102,20 +1214,17 @@ guint obc_session_delete(struct obc_session *session, const char *file,
>                 return 0;
>         }
>
> -       if (session->p != NULL) {
> -               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_BUSY, "Session busy");
> -               return 0;
> -       }
> +       data = g_new0(struct file_data, 1);
> +       data->srcname = g_strdup(file);
>
> -       p = pending_request_new(session, NULL, func, user_data);
> +       p = pending_request_new(session, session_process_delete, data,
> +                                       file_data_free, NULL, func, user_data);
> +       g_queue_push_tail(session->queue, p);
>
> -       p->req_id = g_obex_delete(session->obex, file, async_cb, p, err);
> -       if (*err != NULL) {
> -               pending_request_free(p);
> -               return 0;
> -       }
> +       if (session->queue_complete_id == 0)
> +               session->queue_complete_id = g_idle_add(
> +                                       session_queue_complete, session);

Those line above repeat for every you queue the operations so perhaps
we need a helper functions or just make pending_request_new to do this
automatically. Btw I think you can split this into multiple patches,
you can probably pass NULL as process callback then you add
specialized process callback one by one in the following patches.


--
Luiz Augusto von Dentz
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux