diff options
author | Wim Taymans <wtaymans@redhat.com> | 2015-07-16 18:47:20 +0200 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2015-07-16 18:54:50 +0200 |
commit | eedd9cb7b7ecb50f538f70cd1269ca767bf62140 (patch) | |
tree | 6db3444fdf81393fc1718c8d9cb491a8290e05c2 | |
parent | b4dbb9d7427c27a2297287b5d29b36bd50eb356e (diff) |
devicemonitor: do start and stop outside of the lock
Release the monitor lock when calling the provider start/stop methods.
Because we release the lock now, We need to make sure we check the
cookie again and keep track of started and removed providers.
-rw-r--r-- | gst/gstdevicemonitor.c | 84 |
1 files changed, 71 insertions, 13 deletions
diff --git a/gst/gstdevicemonitor.c b/gst/gstdevicemonitor.c index 994263a45..a07c6d8f0 100644 --- a/gst/gstdevicemonitor.c +++ b/gst/gstdevicemonitor.c @@ -343,7 +343,8 @@ again: gboolean gst_device_monitor_start (GstDeviceMonitor * monitor) { - guint i; + guint cookie, i; + GList *pending = NULL, *started = NULL, *removed = NULL; g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE); @@ -365,28 +366,73 @@ gst_device_monitor_start (GstDeviceMonitor * monitor) gst_bus_set_flushing (monitor->priv->bus, FALSE); +again: + cookie = monitor->priv->cookie; + + g_list_free_full (pending, gst_object_unref); + pending = NULL; + removed = started; + started = NULL; + for (i = 0; i < monitor->priv->providers->len; i++) { - GstDeviceProvider *provider = - g_ptr_array_index (monitor->priv->providers, i); + GstDeviceProvider *provider; + GList *find; + + provider = g_ptr_array_index (monitor->priv->providers, i); + + find = g_list_find (removed, provider); + if (find) { + /* this was already started, move to started list */ + removed = g_list_remove_link (removed, find); + started = g_list_concat (started, find); + } else { + /* not started, add to pending list */ + pending = g_list_append (pending, gst_object_ref (provider)); + } + } + g_list_free_full (removed, gst_object_unref); + removed = NULL; + + while (pending) { + GstDeviceProvider *provider = pending->data; if (gst_device_provider_can_monitor (provider)) { - if (!gst_device_provider_start (provider)) { - gst_bus_set_flushing (monitor->priv->bus, TRUE); + GST_OBJECT_UNLOCK (monitor); - for (; i != 0; i--) - gst_device_provider_stop (g_ptr_array_index (monitor->priv->providers, - i - 1)); + if (!gst_device_provider_start (provider)) + goto start_failed; - GST_OBJECT_UNLOCK (monitor); - return FALSE; - } + GST_OBJECT_LOCK (monitor); } - } + started = g_list_prepend (started, provider); + pending = g_list_delete_link (pending, pending); + if (monitor->priv->cookie != cookie) + goto again; + } monitor->priv->started = TRUE; GST_OBJECT_UNLOCK (monitor); + g_list_free_full (started, gst_object_unref); + return TRUE; + +start_failed: + { + GST_OBJECT_LOCK (monitor); + gst_bus_set_flushing (monitor->priv->bus, TRUE); + GST_OBJECT_UNLOCK (monitor); + + while (started) { + GstDeviceProvider *provider = started->data; + + gst_device_provider_stop (provider); + gst_object_unref (provider); + + started = g_list_delete_link (started, started); + } + return FALSE; + } } /** @@ -401,6 +447,7 @@ void gst_device_monitor_stop (GstDeviceMonitor * monitor) { guint i; + GList *started = NULL; g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor)); @@ -411,9 +458,21 @@ gst_device_monitor_stop (GstDeviceMonitor * monitor) GstDeviceProvider *provider = g_ptr_array_index (monitor->priv->providers, i); + started = g_list_prepend (started, gst_object_ref (provider)); + } + GST_OBJECT_UNLOCK (monitor); + + while (started) { + GstDeviceProvider *provider = started->data; + if (gst_device_provider_can_monitor (provider)) gst_device_provider_stop (provider); + + started = g_list_delete_link (started, started); + gst_object_unref (provider); } + + GST_OBJECT_LOCK (monitor); monitor->priv->started = FALSE; GST_OBJECT_UNLOCK (monitor); @@ -463,7 +522,6 @@ gst_device_monitor_add_filter (GstDeviceMonitor * monitor, while (factories) { GstDeviceProviderFactory *factory = factories->data; - if (gst_device_provider_factory_has_classesv (factory, filter->classesv)) { GstDeviceProvider *provider; |