plugin: allow cancellation of the port probe operation

This commit is contained in:
Aleksander Morgado
2016-01-15 17:54:51 +01:00
parent fd4fdbf21b
commit d3bf07e7a8
3 changed files with 117 additions and 130 deletions

View File

@@ -465,6 +465,7 @@ plugin_supports_port_ready (MMPlugin *plugin,
/* Get supports check results */
support_result = mm_plugin_supports_port_finish (plugin, res, &error);
if (error) {
g_assert_cmpuint (support_result, ==, MM_PLUGIN_SUPPORTS_PORT_UNKNOWN);
mm_warn ("[plugin manager] task %s: error when checking support with plugin '%s': '%s'",
port_context->name, mm_plugin_get_name (plugin), error->message);
g_error_free (error);
@@ -474,6 +475,7 @@ plugin_supports_port_ready (MMPlugin *plugin,
case MM_PLUGIN_SUPPORTS_PORT_SUPPORTED:
port_context_supported (port_context, plugin);
break;
case MM_PLUGIN_SUPPORTS_PORT_UNKNOWN:
case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED:
port_context_unsupported (port_context, plugin);
break;
@@ -518,6 +520,7 @@ port_context_next (PortContext *port_context)
mm_plugin_supports_port (plugin,
port_context->device,
port_context->port,
port_context->cancellable,
(GAsyncReadyCallback) plugin_supports_port_ready,
port_context_ref (port_context));
}

View File

@@ -582,125 +582,119 @@ apply_post_probing_filters (MMPlugin *self,
/* Context for the asynchronous probing operation */
typedef struct {
GSimpleAsyncResult *result;
MMPlugin *self;
MMPortProbeFlag flags;
MMDevice *device;
MMPortProbeFlag flags;
} PortProbeRunContext;
static void
port_probe_run_context_free (PortProbeRunContext *ctx)
{
g_object_unref (ctx->device);
g_object_unref (ctx->self);
g_slice_free (PortProbeRunContext, ctx);
}
static void
port_probe_run_ready (MMPortProbe *probe,
GAsyncResult *probe_result,
PortProbeRunContext *ctx)
GTask *task)
{
GError *error = NULL;
MMPluginSupportsResult result = MM_PLUGIN_SUPPORTS_PORT_UNKNOWN;
PortProbeRunContext *ctx;
if (!mm_port_probe_run_finish (probe, probe_result, &error)) {
/* Probing failed saying the port is unsupported. This is not to be
* treated as a generic error, the plugin is just telling us as nicely
* as it can that the port is not supported, so don't warn these cases.
*/
if (g_error_matches (error,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED)) {
g_simple_async_result_set_op_res_gpointer (ctx->result,
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED),
NULL);
g_error_free (error);
if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
goto out;
}
/* Probing failed but the plugin tells us to retry; so we'll defer the
* probing a bit */
else if (g_error_matches (error,
MM_CORE_ERROR,
MM_CORE_ERROR_RETRY)) {
g_simple_async_result_set_op_res_gpointer (ctx->result,
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER),
NULL);
g_error_free (error);
if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) {
result = MM_PLUGIN_SUPPORTS_PORT_DEFER;
goto out;
}
/* For remaining errors, just propagate them */
else {
g_simple_async_result_take_error (ctx->result, error);
}
} else {
/* Probing succeeded */
MMPluginSupportsResult supports_result;
if (!apply_post_probing_filters (ctx->self, ctx->flags, probe)) {
/* Port is supported! */
supports_result = MM_PLUGIN_SUPPORTS_PORT_SUPPORTED;
/* If we were looking for AT ports, and the port is AT,
* and we were told that only one AT port is expected, cancel AT
* probings in the other available support tasks of the SAME
* device. */
if (ctx->self->priv->single_at &&
ctx->flags & MM_PORT_PROBE_AT &&
mm_port_probe_is_at (probe)) {
GList *l;
for (l = mm_device_peek_port_probe_list (ctx->device); l; l = g_list_next (l)) {
if (l->data != probe) {
mm_port_probe_run_cancel_at_probing (MM_PORT_PROBE (l->data));
}
}
}
} else {
/* Unsupported port, remove from internal tracking HT */
supports_result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
g_simple_async_result_set_op_res_gpointer (ctx->result,
GUINT_TO_POINTER (supports_result),
NULL);
g_task_return_error (task, error);
g_object_unref (task);
return;
}
/* Complete the async supports port request */
g_simple_async_result_complete_in_idle (ctx->result);
/* Probing succeeded, recover context */
ctx = g_task_get_task_data (task);
g_object_unref (ctx->device);
g_object_unref (ctx->result);
g_object_unref (ctx->self);
g_free (ctx);
/* Apply post probing filters */
if (!apply_post_probing_filters (ctx->self, ctx->flags, probe)) {
/* Port is supported! */
result = MM_PLUGIN_SUPPORTS_PORT_SUPPORTED;
/* If we were looking for AT ports, and the port is AT,
* and we were told that only one AT port is expected, cancel AT
* probings in the other available support tasks of the SAME
* device. */
if (ctx->self->priv->single_at &&
ctx->flags & MM_PORT_PROBE_AT &&
mm_port_probe_is_at (probe)) {
GList *l;
for (l = mm_device_peek_port_probe_list (ctx->device); l; l = g_list_next (l)) {
if (l->data != probe)
mm_port_probe_run_cancel_at_probing (MM_PORT_PROBE (l->data));
}
}
} else
/* Filtered by post probing filters */
result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
out:
/* Complete action */
g_clear_error (&error);
g_task_return_int (task, result);
g_object_unref (task);
}
G_STATIC_ASSERT (MM_PLUGIN_SUPPORTS_PORT_UNKNOWN == -1);
MMPluginSupportsResult
mm_plugin_supports_port_finish (MMPlugin *self,
GAsyncResult *result,
GError **error)
mm_plugin_supports_port_finish (MMPlugin *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (MM_IS_PLUGIN (self),
MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result),
MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED);
g_return_val_if_fail (MM_IS_PLUGIN (self), MM_PLUGIN_SUPPORTS_PORT_UNKNOWN);
g_return_val_if_fail (G_IS_TASK (result), MM_PLUGIN_SUPPORTS_PORT_UNKNOWN);
/* Propagate error, if any */
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) {
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
return (MMPluginSupportsResult) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
return (MMPluginSupportsResult) g_task_propagate_int (G_TASK (result), error);
}
void
mm_plugin_supports_port (MMPlugin *self,
MMDevice *device,
GUdevDevice *port,
GAsyncReadyCallback callback,
gpointer user_data)
mm_plugin_supports_port (MMPlugin *self,
MMDevice *device,
GUdevDevice *port,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMPortProbe *probe = NULL;
GSimpleAsyncResult *async_result;
GTask *task;
PortProbeRunContext *ctx;
gboolean need_vendor_probing;
gboolean need_product_probing;
MMPortProbeFlag probe_run_flags;
gchar *probe_list_str;
async_result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
mm_plugin_supports_port);
g_return_if_fail (MM_IS_PLUGIN (self));
g_return_if_fail (MM_IS_DEVICE (device));
g_return_if_fail (G_UDEV_IS_DEVICE (port));
/* Create new cancellable task */
task = g_task_new (self, cancellable, callback, user_data);
/* Apply filters before launching the probing */
if (apply_pre_probing_filters (self,
@@ -709,46 +703,40 @@ mm_plugin_supports_port (MMPlugin *self,
&need_vendor_probing,
&need_product_probing)) {
/* Filtered! */
g_simple_async_result_set_op_res_gpointer (async_result,
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED),
NULL);
g_simple_async_result_complete_in_idle (async_result);
goto out;
g_task_return_int (task, MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED);
g_object_unref (task);
return;
}
/* Need to launch new probing */
probe = MM_PORT_PROBE (mm_device_get_port_probe (device, port));
probe = MM_PORT_PROBE (mm_device_peek_port_probe (device, port));
if (!probe) {
/* This may happen if the ports get removed from the device while
* probing is ongoing */
g_simple_async_result_set_error (async_result,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"(%s) Missing port probe for port (%s/%s)",
self->priv->name,
g_udev_device_get_subsystem (port),
g_udev_device_get_name (port));
g_simple_async_result_complete_in_idle (async_result);
goto out;
g_task_return_new_error (task,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"(%s) Missing port probe for port (%s/%s)",
self->priv->name,
g_udev_device_get_subsystem (port),
g_udev_device_get_name (port));
g_object_unref (task);
return;
}
/* Before launching any probing, check if the port is a net device. */
if (g_str_equal (g_udev_device_get_subsystem (port), "net")) {
mm_dbg ("(%s) [%s] probing deferred until result suggested",
self->priv->name,
g_udev_device_get_name (port));
g_simple_async_result_set_op_res_gpointer (
async_result,
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED),
NULL);
g_simple_async_result_complete_in_idle (async_result);
goto out;
self->priv->name, g_udev_device_get_name (port));
g_task_return_int (task, MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED);
g_object_unref (task);
return;
}
/* Build flags depending on what probing needed */
probe_run_flags = MM_PORT_PROBE_NONE;
if (!g_str_has_prefix (g_udev_device_get_name (port), "cdc-wdm")) {
/* Serial ports... */
probe_run_flags = MM_PORT_PROBE_NONE;
if (self->priv->at)
probe_run_flags |= MM_PORT_PROBE_AT;
else if (self->priv->single_at)
@@ -757,7 +745,6 @@ mm_plugin_supports_port (MMPlugin *self,
probe_run_flags |= MM_PORT_PROBE_QCDM;
} else {
/* cdc-wdm ports... */
probe_run_flags = MM_PORT_PROBE_NONE;
if (self->priv->qmi && !g_strcmp0 (mm_device_utils_get_port_driver (port), "qmi_wwan"))
probe_run_flags |= MM_PORT_PROBE_QMI;
else if (self->priv->mbim && !g_strcmp0 (mm_device_utils_get_port_driver (port), "cdc_mbim"))
@@ -779,11 +766,9 @@ mm_plugin_supports_port (MMPlugin *self,
/* If no explicit probing was required, just request to grab it without probing anything.
* This may happen, e.g. with cdc-wdm ports which do not need QMI/MBIM probing. */
if (probe_run_flags == MM_PORT_PROBE_NONE) {
g_simple_async_result_set_op_res_gpointer (async_result,
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED),
NULL);
g_simple_async_result_complete_in_idle (async_result);
goto out;
g_task_return_int (task, MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED);
g_object_unref (task);
return;
}
/* If a modem is already available and the plugin says that only one AT port is
@@ -803,11 +788,13 @@ mm_plugin_supports_port (MMPlugin *self,
}
/* Setup async call context */
ctx = g_new (PortProbeRunContext, 1);
ctx->self = g_object_ref (self);
ctx = g_slice_new0 (PortProbeRunContext);
ctx->self = g_object_ref (self);
ctx->device = g_object_ref (device);
ctx->result = g_object_ref (async_result);
ctx->flags = probe_run_flags;
ctx->flags = probe_run_flags;
/* Store context in task */
g_task_set_task_data (task, ctx, (GDestroyNotify) port_probe_run_context_free);
/* Launch the probe */
probe_list_str = mm_port_probe_flag_build_string_from_mask (ctx->flags);
@@ -824,13 +811,8 @@ mm_plugin_supports_port (MMPlugin *self,
self->priv->send_lf,
self->priv->custom_at_probe,
self->priv->custom_init,
(GAsyncReadyCallback)port_probe_run_ready,
ctx);
out:
g_object_unref (async_result);
if (probe)
g_object_unref (probe);
(GAsyncReadyCallback) port_probe_run_ready,
task);
}
/*****************************************************************************/

View File

@@ -64,7 +64,8 @@
#define MM_PLUGIN_SEND_LF "send-lf"
typedef enum {
MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED = 0x0,
MM_PLUGIN_SUPPORTS_PORT_UNKNOWN = -1,
MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED,
MM_PLUGIN_SUPPORTS_PORT_DEFER,
MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED,
MM_PLUGIN_SUPPORTS_PORT_SUPPORTED
@@ -119,14 +120,15 @@ MMPluginSupportsHint mm_plugin_discard_port_early (MMPlugin *plugin,
MMDevice *device,
GUdevDevice *port);
void mm_plugin_supports_port (MMPlugin *plugin,
MMDevice *device,
GUdevDevice *port,
GAsyncReadyCallback callback,
gpointer user_data);
MMPluginSupportsResult mm_plugin_supports_port_finish (MMPlugin *plugin,
GAsyncResult *result,
GError **error);
void mm_plugin_supports_port (MMPlugin *plugin,
MMDevice *device,
GUdevDevice *port,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
MMPluginSupportsResult mm_plugin_supports_port_finish (MMPlugin *plugin,
GAsyncResult *result,
GError **error);
MMBaseModem *mm_plugin_create_modem (MMPlugin *plugin,
MMDevice *device,