summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2017-11-25 11:15:54 +0100
committerAleksander Morgado <aleksander@aleksander.es>2017-11-27 12:55:27 +0100
commitcc8587fa012aa6f65e6c47a5a2b8e37d79a9c004 (patch)
treea449b0bd59d091affeb11af56b98fe3e9e1120d0
parent1152cf7e6a4a96d833b6ab0a58c5fc6e3ea54765 (diff)
libqmi-glib,client: new 'client-valid' property
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. ... [/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.
-rw-r--r--build-aux/qmi-codegen/Client.py5
-rw-r--r--docs/reference/libqmi-glib/libqmi-glib-common.sections2
-rw-r--r--src/libqmi-glib/qmi-client.c27
-rw-r--r--src/libqmi-glib/qmi-client.h28
-rw-r--r--src/libqmi-glib/qmi-device.c2
5 files changed, 63 insertions, 1 deletions
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
};
@@ -93,6 +94,16 @@ qmi_client_get_cid (QmiClient *self)
}
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,
guint *minor)
@@ -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
@@ -122,6 +122,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:
*
* The #QmiClient structure contains private data and should only be accessed
@@ -196,6 +205,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
* @major: placeholder for the output major version.
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,