[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