[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