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

View File

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

View File

@@ -64,7 +64,8 @@
#define MM_PLUGIN_SEND_LF "send-lf" #define MM_PLUGIN_SEND_LF "send-lf"
typedef enum { 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,
MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED, MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED,
MM_PLUGIN_SUPPORTS_PORT_SUPPORTED MM_PLUGIN_SUPPORTS_PORT_SUPPORTED
@@ -122,6 +123,7 @@ MMPluginSupportsHint mm_plugin_discard_port_early (MMPlugin *plugin,
void mm_plugin_supports_port (MMPlugin *plugin, void mm_plugin_supports_port (MMPlugin *plugin,
MMDevice *device, MMDevice *device,
GUdevDevice *port, GUdevDevice *port,
GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
MMPluginSupportsResult mm_plugin_supports_port_finish (MMPlugin *plugin, MMPluginSupportsResult mm_plugin_supports_port_finish (MMPlugin *plugin,