[PATCH 6/8] libqmi-glib, device: port qmi_device_release_client to use GTask

Ben Chan benchan at chromium.org
Tue Apr 18 14:49:20 UTC 2017


On Tue, Apr 18, 2017 at 7:47 AM, Ben Chan <benchan at chromium.org> wrote:
> On Tue, Apr 18, 2017 at 6:58 AM, Aleksander Morgado
> <aleksander at aleksander.es> wrote:
>>
>> Hey Ben,
>>
>> See below.
>>
>> On 12/04/17 22:15, Ben Chan wrote:
>> > ---
>> >  src/libqmi-glib/qmi-device.c | 56 ++++++++++++++------------------------------
>> >  1 file changed, 18 insertions(+), 38 deletions(-)
>> >
>> > diff --git a/src/libqmi-glib/qmi-device.c b/src/libqmi-glib/qmi-device.c
>> > index 108b605..bc9480c 100644
>> > --- a/src/libqmi-glib/qmi-device.c
>> > +++ b/src/libqmi-glib/qmi-device.c
>> > @@ -1120,32 +1120,18 @@ qmi_device_allocate_client (QmiDevice *self,
>> >  /*****************************************************************************/
>> >  /* Release client */
>> >
>> > -typedef struct {
>> > -    QmiClient *client;
>> > -    GSimpleAsyncResult *result;
>> > -} ReleaseClientContext;
>> > -
>> > -static void
>> > -release_client_context_complete_and_free (ReleaseClientContext *ctx)
>> > -{
>> > -    g_simple_async_result_complete_in_idle (ctx->result);
>> > -    g_object_unref (ctx->result);
>> > -    g_object_unref (ctx->client);
>> > -    g_slice_free (ReleaseClientContext, ctx);
>> > -}
>> > -
>> >  gboolean
>> >  qmi_device_release_client_finish (QmiDevice *self,
>> >                                    GAsyncResult *res,
>> >                                    GError **error)
>> >  {
>> > -    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
>> > +    return g_task_propagate_boolean (G_TASK (res), error);
>> >  }
>> >
>> >  static void
>> >  client_ctl_release_cid_ready (QmiClientCtl *client_ctl,
>> >                                GAsyncResult *res,
>> > -                              ReleaseClientContext *ctx)
>> > +                              GTask *task)
>> >  {
>> >      GError *error = NULL;
>> >      QmiMessageCtlReleaseCidOutput *output;
>> > @@ -1156,21 +1142,21 @@ client_ctl_release_cid_ready (QmiClientCtl *client_ctl,
>> >      /* Check result of the async operation */
>> >      output = qmi_client_ctl_release_cid_finish (client_ctl, res, &error);
>> >      if (!output) {
>> > -        g_simple_async_result_take_error (ctx->result, error);
>> > -        release_client_context_complete_and_free (ctx);
>> > +        g_task_return_error (task, error);
>> > +        g_object_unref (task);
>> >          return;
>> >      }
>> >
>> >      /* Check result of the QMI operation */
>> >      if (!qmi_message_ctl_release_cid_output_get_result (output, &error)) {
>> > -        g_simple_async_result_take_error (ctx->result, error);
>> > -        release_client_context_complete_and_free (ctx);
>> > +        g_task_return_error (task, error);
>> > +        g_object_unref (task);
>> >          qmi_message_ctl_release_cid_output_unref (output);
>> >          return;
>> >      }
>> >
>> > -    g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
>> > -    release_client_context_complete_and_free (ctx);
>> > +    g_task_return_boolean (task, TRUE);
>> > +    g_object_unref (task);
>> >      qmi_message_ctl_release_cid_output_unref (output);
>> >  }
>> >
>> > @@ -1183,7 +1169,7 @@ qmi_device_release_client (QmiDevice *self,
>> >                             GAsyncReadyCallback callback,
>> >                             gpointer user_data)
>> >  {
>> > -    ReleaseClientContext *ctx;
>> > +    GTask *task;
>> >      QmiService service;
>> >      guint8 cid;
>> >      gchar *flags_str;
>> > @@ -1206,21 +1192,15 @@ qmi_device_release_client (QmiDevice *self,
>> >
>> >      /* NOTE! The operation must not take a reference to self, or we won't be
>> >       * able to use it implicitly from our dispose() */
>>
>> This previous comment is misleading and obsolete, and we should remove
>> it. There is no explicit CID releasing done during dispose(), and
>> therefore we can (must I would say) take a reference to self in the GTask.
>>
>> > -
>> > -    ctx = g_slice_new0 (ReleaseClientContext);
>> > -    ctx->client = g_object_ref (client);
>> > -    ctx->result = g_simple_async_result_new (G_OBJECT (self),
>> > -                                             callback,
>> > -                                             user_data,
>> > -                                             qmi_device_release_client);
>> > +    task = g_task_new (client, cancellable, callback, user_data);
>> >
>>
>> The source_object for the GTask *must* be 'self', not 'client'. This is
>> because during the task completion, the first argument given to the
>> finish() function will be this object and that would be a QmiDevice.
>> Now, this is really not required as the pointer is anyway not used in
>> the finish() method, but we should keep it consistent.
>>
>> And if we do this, beware, because a bit further down in the logic there
>> is a unregister_client() call that will remove the internal reference to
>> the client (and therefore may be the last one), and just after that we
>> do a g_object_set() on the client object. This worked always before
>> because there was a client reference in the Context; but now there
>> isn't. We cannot remove the g_object_set() call, as we don't know
>> whether the caller holds a full reference or not, so the correct thing
>> to do would be to make sure there is an explicit valid reference to the
>> client object around those calls; or just set a full client reference as
>> task data.
>>
>
> How about we put unregister_client after g_object_set?

I guess not, as unregister_client needs to obtain CID and SERVICE from
client to derive the key.

>
> Looking from another angle, should the caller keep a reference to client?
>
>> >      /* Do not try to release an already released client */
>> >      if (cid == QMI_CID_NONE) {
>> > -        g_simple_async_result_set_error (ctx->result,
>> > -                                         QMI_CORE_ERROR,
>> > -                                         QMI_CORE_ERROR_INVALID_ARGS,
>> > -                                         "Client is already released");
>> > -        release_client_context_complete_and_free (ctx);
>> > +        g_task_return_new_error (task,
>> > +                                 QMI_CORE_ERROR,
>> > +                                 QMI_CORE_ERROR_INVALID_ARGS,
>> > +                                 "Client is already released");
>> > +        g_object_unref (task);
>> >          return;
>> >      }
>> >
>> > @@ -1252,15 +1232,15 @@ qmi_device_release_client (QmiDevice *self,
>> >                                      timeout,
>> >                                      cancellable,
>> >                                      (GAsyncReadyCallback)client_ctl_release_cid_ready,
>> > -                                    ctx);
>> > +                                    task);
>> >
>> >          qmi_message_ctl_release_cid_input_unref (input);
>> >          return;
>> >      }
>> >
>> >      /* No need to release the CID, so just done */
>> > -    g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
>> > -    release_client_context_complete_and_free (ctx);
>> > +    g_task_return_boolean (task, TRUE);
>> > +    g_object_unref (task);
>> >      return;
>> >  }
>> >
>> >
>>
>>
>> --
>> Aleksander
>> https://aleksander.es


More information about the libqmi-devel mailing list