[PATCH] libqmi-glib,client: new 'client-valid' property

Dan Williams dcbw at redhat.com
Mon Nov 27 03:02:49 UTC 2017


On Sat, 2017-11-25 at 11:34 +0100, Aleksander Morgado wrote:
> It may happen that the lifecycle of a QmiDevice and its allocated
> QmiClients is managed in a different place of where the QmiClient
> commands are run, which may keep a QmiClient reference of its own.
> 
> In this setup, it may happen that the QmiDevice is closed and all
> clients released while there are still full QmiClient references
> around that the client may try to use. When this happens, the client
> operation didn't fail with an error, instead it would just issue a
> 'QMI_IS_DEVICE (self)' failed warning and go on.

LGTM

>     ...
>     [/dev/cdc-wdm0] Releasing 'dms' client with flags 'release-
> cid'...
>     [/dev/cdc-wdm0] Unregistered 'dms' client with ID '10'
>     [/dev/cdc-wdm0] sent message...
>     <<<<<< RAW:
>     <<<<<<   length = 17
>     <<<<<<   data   =
> 01:10:00:00:00:00:00:0C:23:00:05:00:01:02:00:02:0A
>     [/dev/cdc-wdm0] sent generic request (translated)...
>     <<<<<< QMUX:
>     <<<<<<   length  = 16
>     <<<<<<   flags   = 0x00
>     <<<<<<   service = "ctl"
>     <<<<<<   client  = 0
>     <<<<<< QMI:
>     <<<<<<   flags       = "none"
>     <<<<<<   transaction = 12
>     <<<<<<   tlv_length  = 5
>     <<<<<<   message     = "Release CID" (0x0023)
>     <<<<<< TLV:
>     <<<<<<   type       = "Release Info" (0x01)
>     <<<<<<   length     = 2
>     <<<<<<   value      = 02:0A
>     <<<<<<   translated = [ service = 'dms' cid = '10' ]
>     qmi_device_command_full: assertion 'QMI_IS_DEVICE (self)' failed
>     <warn>  [062790.772245] checking if connected failed: Transaction
> timed out
>     <debug> [062793.774332] Couldn't refresh CDMA registration
> status: 'QMI operation failed: Transaction timed out'
>     <debug> [062793.774398] Couldn't refresh signal quality:
> 'Transaction timed out'
>     <debug> [062793.774414] Periodic signal checks not rescheduled:
> disabled
>     qmi_device_command_full: assertion 'QMI_IS_DEVICE (self)' failed
>     <warn>  [062795.773381] Reloading stats failed: QMI operation
> failed: Transaction timed out
>     <warn>  [062795.773425] checking if connected failed: Transaction
> timed out
>     qmi_device_command_full: assertion 'QMI_IS_DEVICE (self)' failed
>     qmi_device_command_full: assertion 'QMI_IS_DEVICE (self)' failed
>     ...
> 
> We avoid this situation by exposing a new 'client-valid' property
> that
> users may check before running any command.
> 
> This same check is now also internally done by all commands so that
> we
> cleanly error out if we detect that the client isn't valid.
> ---
>  build-aux/qmi-codegen/Client.py                    |  5 ++++
>  .../libqmi-glib/libqmi-glib-common.sections        |  2 ++
>  src/libqmi-glib/qmi-client.c                       | 27
> +++++++++++++++++++++
>  src/libqmi-glib/qmi-client.h                       | 28
> ++++++++++++++++++++++
>  src/libqmi-glib/qmi-device.c                       |  2 +-
>  5 files changed, 63 insertions(+), 1 deletion(-)
> 
> diff --git a/build-aux/qmi-codegen/Client.py b/build-aux/qmi-
> codegen/Client.py
> index 445c862..be51197 100644
> --- a/build-aux/qmi-codegen/Client.py
> +++ b/build-aux/qmi-codegen/Client.py
> @@ -477,6 +477,11 @@ class Client:
>              template += (
>                  '\n'
>                  '    task = g_task_new (self, cancellable, callback,
> user_data);\n'
> +                '    if (!qmi_client_is_valid (QMI_CLIENT (self)))
> {\n'
> +                '        g_task_return_new_error (task,
> QMI_CORE_ERROR, QMI_CORE_ERROR_WRONG_STATE, "client invalid");\n'
> +                '        g_object_unref (task);\n'
> +                '        return;\n'
> +                '    }\n'
>                  '\n'
>                  '    transaction_id =
> qmi_client_get_next_transaction_id (QMI_CLIENT (self));\n'
>                  '\n'
> diff --git a/docs/reference/libqmi-glib/libqmi-glib-common.sections
> b/docs/reference/libqmi-glib/libqmi-glib-common.sections
> index 6ce1e37..bc088e7 100644
> --- a/docs/reference/libqmi-glib/libqmi-glib-common.sections
> +++ b/docs/reference/libqmi-glib/libqmi-glib-common.sections
> @@ -18,11 +18,13 @@ QMI_CLIENT_SERVICE
>  QMI_CLIENT_CID
>  QMI_CLIENT_VERSION_MAJOR
>  QMI_CLIENT_VERSION_MINOR
> +QMI_CLIENT_VALID
>  QmiClient
>  qmi_client_get_device
>  qmi_client_peek_device
>  qmi_client_get_service
>  qmi_client_get_cid
> +qmi_client_is_valid
>  qmi_client_get_version
>  qmi_client_check_version
>  qmi_client_get_next_transaction_id
> diff --git a/src/libqmi-glib/qmi-client.c b/src/libqmi-glib/qmi-
> client.c
> index 4c0c5c3..5a9c3a3 100644
> --- a/src/libqmi-glib/qmi-client.c
> +++ b/src/libqmi-glib/qmi-client.c
> @@ -37,6 +37,7 @@ enum {
>      PROP_CID,
>      PROP_VERSION_MAJOR,
>      PROP_VERSION_MINOR,
> +    PROP_VALID,
>      PROP_LAST
>  };
>  
> @@ -92,6 +93,16 @@ qmi_client_get_cid (QmiClient *self)
>      return self->priv->cid;
>  }
>  
> +gboolean
> +qmi_client_is_valid (QmiClient *self)
> +{
> +    g_return_val_if_fail (QMI_IS_CLIENT (self), FALSE);
> +
> +    return (self->priv->service != QMI_SERVICE_UNKNOWN &&
> +            QMI_IS_DEVICE (self->priv->device) &&
> +            ((self->priv->cid != QMI_CID_NONE || self->priv->service 
> == QMI_SERVICE_CTL)));
> +}
> +
>  gboolean
>  qmi_client_get_version (QmiClient *self,
>                          guint *major,
> @@ -218,6 +229,9 @@ get_property (GObject *object,
>      case PROP_VERSION_MINOR:
>          g_value_set_uint (value, self->priv->version_minor);
>          break;
> +    case PROP_VALID:
> +        g_value_set_boolean (value, qmi_client_is_valid (self));
> +        break;
>      default:
>          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
>          break;
> @@ -320,4 +334,17 @@ qmi_client_class_init (QmiClientClass *klass)
>                             0,
>                             G_PARAM_READWRITE);
>      g_object_class_install_property (object_class,
> PROP_VERSION_MINOR, properties[PROP_VERSION_MINOR]);
> +
> +    /**
> +     * QmiClient:client-valid:
> +     *
> +     * Since: 1.20
> +     */
> +    properties[PROP_VALID] =
> +        g_param_spec_boolean (QMI_CLIENT_VALID,
> +                              "Valid",
> +                              "Whether the client is valid and
> usable",
> +                              FALSE,
> +                              G_PARAM_READABLE);
> +    g_object_class_install_property (object_class, PROP_VALID,
> properties[PROP_VALID]);
>  }
> diff --git a/src/libqmi-glib/qmi-client.h b/src/libqmi-glib/qmi-
> client.h
> index c8f81fd..52ef1c4 100644
> --- a/src/libqmi-glib/qmi-client.h
> +++ b/src/libqmi-glib/qmi-client.h
> @@ -121,6 +121,15 @@ typedef struct _QmiClientPrivate
> QmiClientPrivate;
>   */
>  #define QMI_CLIENT_VERSION_MINOR "client-version-minor"
>  
> +/**
> + * QMI_CLIENT_VALID:
> + *
> + * Symbol defining the #QmiClient:valid property.
> + *
> + * Since: 1.20
> + */
> +#define QMI_CLIENT_VALID "client-valid"
> +
>  /**
>   * QmiClient:
>   *
> @@ -195,6 +204,25 @@ QmiService qmi_client_get_service (QmiClient
> *self);
>   */
>  guint8 qmi_client_get_cid (QmiClient *self);
>  
> +/**
> + * qmi_client_is_valid:
> + * @self: a #QmiClient.
> + *
> + * Checks whether #QmiClient is a valid and usable client.
> + *
> + * The client is marked as invalid as soon as the client id is
> released or when
> + * the associated #QmiDevice is closed.
> + *
> + * This method may be used if the caller needs to ensure validity
> before a
> + * command is attempted, e.g. if the lifecycle of the object is
> managed in some
> + * other place and the caller just has a reference to the
> #QmiClient.
> + *
> + * Returns: %TRUE if the client is valid, %FALSE otherwise.
> + *
> + * Since: 1.20
> + */
> +gboolean qmi_client_is_valid (QmiClient *self);
> +
>  /**
>   * qmi_client_get_version:
>   * @self: A #QmiClient
> diff --git a/src/libqmi-glib/qmi-device.c b/src/libqmi-glib/qmi-
> device.c
> index e98f3ca..2bf6a40 100644
> --- a/src/libqmi-glib/qmi-device.c
> +++ b/src/libqmi-glib/qmi-device.c
> @@ -1219,7 +1219,7 @@ qmi_device_release_client (QmiDevice *self,
>               qmi_service_get_string (service),
>               cid);
>  
> -    /* Reset the contents of the client object, making it unusable
> */
> +    /* Reset the contents of the client object, making it invalid */
>      g_object_set (client,
>                    QMI_CLIENT_CID,     QMI_CID_NONE,
>                    QMI_CLIENT_SERVICE, QMI_SERVICE_UNKNOWN,


More information about the libqmi-devel mailing list