rtmp2: Lock self->lock before OBJECT_LOCK

OBJECT_LOCK is used to protect property access only. self->lock is
used to access the RtmpConnection, mostly between the streaming thread
and the loop thread.

To avoid deadlocks involving these two locks, we obey a lock order:
If both self->lock and OBJECT_LOCK are needed, self->lock must be locked
first. Clarify this.
This commit is contained in:
Jan Alexander Steffens (heftig) 2020-02-14 14:26:27 +01:00 committed by GStreamer Merge Bot
parent 6583e00d50
commit 14fd7e0884
2 changed files with 28 additions and 19 deletions

View file

@ -66,11 +66,13 @@ typedef struct
gboolean async_connect; gboolean async_connect;
guint peak_kbps; guint peak_kbps;
/* stuff */ /* If both self->lock and OBJECT_LOCK are needed,
gboolean running, flushing; * self->lock must be taken first */
GMutex lock; GMutex lock;
GCond cond; GCond cond;
gboolean running, flushing;
GstTask *task; GstTask *task;
GRecMutex task_lock; GRecMutex task_lock;
@ -309,11 +311,12 @@ gst_rtmp2_sink_set_property (GObject * object, guint property_id,
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
break; break;
case PROP_PEAK_KBPS: case PROP_PEAK_KBPS:
g_mutex_lock (&self->lock);
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
self->peak_kbps = g_value_get_uint (value); self->peak_kbps = g_value_get_uint (value);
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
g_mutex_lock (&self->lock);
set_pacing_rate (self); set_pacing_rate (self);
g_mutex_unlock (&self->lock); g_mutex_unlock (&self->lock);
break; break;
@ -838,38 +841,40 @@ gst_rtmp2_sink_task_func (gpointer user_data)
GTask *connector; GTask *connector;
GST_DEBUG_OBJECT (self, "gst_rtmp2_sink_task starting"); GST_DEBUG_OBJECT (self, "gst_rtmp2_sink_task starting");
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
context = self->context = g_main_context_new (); context = self->context = g_main_context_new ();
g_main_context_push_thread_default (context); g_main_context_push_thread_default (context);
loop = self->loop = g_main_loop_new (context, TRUE); loop = self->loop = g_main_loop_new (context, TRUE);
connector = g_task_new (self, self->cancellable, connect_task_done, NULL); connector = g_task_new (self, self->cancellable, connect_task_done, NULL);
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
gst_rtmp_client_connect_async (&self->location, self->cancellable, gst_rtmp_client_connect_async (&self->location, self->cancellable,
client_connect_done, connector); client_connect_done, connector);
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
/* Run loop */
g_mutex_unlock (&self->lock); g_mutex_unlock (&self->lock);
g_main_loop_run (loop); g_main_loop_run (loop);
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
g_clear_pointer (&self->loop, g_main_loop_unref); g_clear_pointer (&self->loop, g_main_loop_unref);
g_clear_pointer (&self->connection, gst_rtmp_connection_close_and_unref); g_clear_pointer (&self->connection, gst_rtmp_connection_close_and_unref);
g_cond_broadcast (&self->cond); g_cond_broadcast (&self->cond);
g_mutex_unlock (&self->lock);
/* Run loop cleanup */
g_mutex_unlock (&self->lock);
while (g_main_context_pending (context)) { while (g_main_context_pending (context)) {
GST_DEBUG_OBJECT (self, "iterating main context to clean up"); GST_DEBUG_OBJECT (self, "iterating main context to clean up");
g_main_context_iteration (context, FALSE); g_main_context_iteration (context, FALSE);
} }
g_main_context_pop_thread_default (context); g_main_context_pop_thread_default (context);
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
g_clear_pointer (&self->context, g_main_context_unref); g_clear_pointer (&self->context, g_main_context_unref);
g_ptr_array_set_size (self->headers, 0); g_ptr_array_set_size (self->headers, 0);
g_mutex_unlock (&self->lock);
g_mutex_unlock (&self->lock);
GST_DEBUG_OBJECT (self, "gst_rtmp2_sink_task exiting"); GST_DEBUG_OBJECT (self, "gst_rtmp2_sink_task exiting");
} }

View file

@ -60,11 +60,13 @@ typedef struct
GstRtmpLocation location; GstRtmpLocation location;
gboolean async_connect; gboolean async_connect;
/* stuff */ /* If both self->lock and OBJECT_LOCK are needed,
gboolean running, flushing; * self->lock must be taken first */
GMutex lock; GMutex lock;
GCond cond; GCond cond;
gboolean running, flushing;
GstTask *task; GstTask *task;
GRecMutex task_lock; GRecMutex task_lock;
@ -599,38 +601,40 @@ gst_rtmp2_src_task_func (gpointer user_data)
GTask *connector; GTask *connector;
GST_DEBUG_OBJECT (self, "gst_rtmp2_src_task starting"); GST_DEBUG_OBJECT (self, "gst_rtmp2_src_task starting");
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
context = self->context = g_main_context_new (); context = self->context = g_main_context_new ();
g_main_context_push_thread_default (context); g_main_context_push_thread_default (context);
loop = self->loop = g_main_loop_new (context, TRUE); loop = self->loop = g_main_loop_new (context, TRUE);
connector = g_task_new (self, self->cancellable, connect_task_done, NULL); connector = g_task_new (self, self->cancellable, connect_task_done, NULL);
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
gst_rtmp_client_connect_async (&self->location, self->cancellable, gst_rtmp_client_connect_async (&self->location, self->cancellable,
client_connect_done, connector); client_connect_done, connector);
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
/* Run loop */
g_mutex_unlock (&self->lock); g_mutex_unlock (&self->lock);
g_main_loop_run (loop); g_main_loop_run (loop);
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
g_clear_pointer (&self->loop, g_main_loop_unref); g_clear_pointer (&self->loop, g_main_loop_unref);
g_clear_pointer (&self->connection, gst_rtmp_connection_close_and_unref); g_clear_pointer (&self->connection, gst_rtmp_connection_close_and_unref);
g_cond_broadcast (&self->cond); g_cond_broadcast (&self->cond);
g_mutex_unlock (&self->lock);
/* Run loop cleanup */
g_mutex_unlock (&self->lock);
while (g_main_context_pending (context)) { while (g_main_context_pending (context)) {
GST_DEBUG_OBJECT (self, "iterating main context to clean up"); GST_DEBUG_OBJECT (self, "iterating main context to clean up");
g_main_context_iteration (context, FALSE); g_main_context_iteration (context, FALSE);
} }
g_main_context_pop_thread_default (context); g_main_context_pop_thread_default (context);
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
g_clear_pointer (&self->context, g_main_context_unref); g_clear_pointer (&self->context, g_main_context_unref);
gst_buffer_replace (&self->message, NULL); gst_buffer_replace (&self->message, NULL);
g_mutex_unlock (&self->lock);
g_mutex_unlock (&self->lock);
GST_DEBUG_OBJECT (self, "gst_rtmp2_src_task exiting"); GST_DEBUG_OBJECT (self, "gst_rtmp2_src_task exiting");
} }