From 1d50e06560d0fad16ef4fc6207ffee2fb6e2a835 Mon Sep 17 00:00:00 2001 From: Lionel Nicolas Date: Tue, 15 Jun 2021 03:15:08 -0400 Subject: [PATCH] Fix deadlock on mountpoint destroy during RTSP reconnect (#2700) --- mutex.h | 36 ++++++++++++++++++++++++------------ plugins/janus_streaming.c | 16 ++++++++++------ 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/mutex.h b/mutex.h index d661628fda..269701fb72 100644 --- a/mutex.h +++ b/mutex.h @@ -28,17 +28,23 @@ typedef pthread_mutex_t janus_mutex; /*! \brief Janus mutex destruction */ #define janus_mutex_destroy(a) pthread_mutex_destroy(a) /*! \brief Janus mutex lock without debug */ -#define janus_mutex_lock_nodebug(a) pthread_mutex_lock(a); +#define janus_mutex_lock_nodebug(a) pthread_mutex_lock(a) /*! \brief Janus mutex lock with debug (prints the line that locked a mutex) */ -#define janus_mutex_lock_debug(a) { JANUS_PRINT("[%s:%s:%d:lock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); pthread_mutex_lock(a); }; +#define janus_mutex_lock_debug(a) { JANUS_PRINT("[%s:%s:%d:lock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); pthread_mutex_lock(a); } /*! \brief Janus mutex lock wrapper (selective locking debug) */ -#define janus_mutex_lock(a) { if(!lock_debug) { janus_mutex_lock_nodebug(a); } else { janus_mutex_lock_debug(a); } }; +#define janus_mutex_lock(a) { if(!lock_debug) { janus_mutex_lock_nodebug(a); } else { janus_mutex_lock_debug(a); } } +/*! \brief Janus mutex try lock without debug */ +#define janus_mutex_trylock_nodebug(a) { ret = pthread_mutex_trylock(a); } +/*! \brief Janus mutex try lock with debug (prints the line that tried to lock a mutex) */ +#define janus_mutex_trylock_debug(a) { JANUS_PRINT("[%s:%s:%d:trylock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); ret = pthread_mutex_trylock(a); } +/*! \brief Janus mutex try lock wrapper (selective locking debug) */ +#define janus_mutex_trylock(a) ({ int ret; if(!lock_debug) { janus_mutex_trylock_nodebug(a); } else { janus_mutex_trylock_debug(a); } ret; }) /*! \brief Janus mutex unlock without debug */ -#define janus_mutex_unlock_nodebug(a) pthread_mutex_unlock(a); +#define janus_mutex_unlock_nodebug(a) pthread_mutex_unlock(a) /*! \brief Janus mutex unlock with debug (prints the line that unlocked a mutex) */ -#define janus_mutex_unlock_debug(a) { JANUS_PRINT("[%s:%s:%d:unlock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); pthread_mutex_unlock(a); }; +#define janus_mutex_unlock_debug(a) { JANUS_PRINT("[%s:%s:%d:unlock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); pthread_mutex_unlock(a); } /*! \brief Janus mutex unlock wrapper (selective locking debug) */ -#define janus_mutex_unlock(a) { if(!lock_debug) { janus_mutex_unlock_nodebug(a); } else { janus_mutex_unlock_debug(a); } }; +#define janus_mutex_unlock(a) { if(!lock_debug) { janus_mutex_unlock_nodebug(a); } else { janus_mutex_unlock_debug(a); } } /*! \brief Janus condition implementation */ typedef pthread_cond_t janus_condition; @@ -72,17 +78,23 @@ typedef GMutex janus_mutex; /*! \brief Janus mutex destruction */ #define janus_mutex_destroy(a) g_mutex_clear(a) /*! \brief Janus mutex lock without debug */ -#define janus_mutex_lock_nodebug(a) g_mutex_lock(a); +#define janus_mutex_lock_nodebug(a) g_mutex_lock(a) /*! \brief Janus mutex lock with debug (prints the line that locked a mutex) */ -#define janus_mutex_lock_debug(a) { JANUS_PRINT("[%s:%s:%d:lock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); g_mutex_lock(a); }; +#define janus_mutex_lock_debug(a) { JANUS_PRINT("[%s:%s:%d:lock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); g_mutex_lock(a); } /*! \brief Janus mutex lock wrapper (selective locking debug) */ -#define janus_mutex_lock(a) { if(!lock_debug) { janus_mutex_lock_nodebug(a); } else { janus_mutex_lock_debug(a); } }; +#define janus_mutex_lock(a) { if(!lock_debug) { janus_mutex_lock_nodebug(a); } else { janus_mutex_lock_debug(a); } } +/*! \brief Janus mutex try lock without debug */ +#define janus_mutex_trylock_nodebug(a) { ret = g_mutex_trylock(a); } +/*! \brief Janus mutex try lock with debug (prints the line that tried to lock a mutex) */ +#define janus_mutex_trylock_debug(a) { JANUS_PRINT("[%s:%s:%d:trylock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); ret = g_mutex_trylock(a); } +/*! \brief Janus mutex try lock wrapper (selective locking debug) */ +#define janus_mutex_trylock(a) ({ gboolean ret; if(!lock_debug) { janus_mutex_trylock_nodebug(a); } else { janus_mutex_trylock_debug(a); } ret; }) /*! \brief Janus mutex unlock without debug */ -#define janus_mutex_unlock_nodebug(a) g_mutex_unlock(a); +#define janus_mutex_unlock_nodebug(a) g_mutex_unlock(a) /*! \brief Janus mutex unlock with debug (prints the line that unlocked a mutex) */ -#define janus_mutex_unlock_debug(a) { JANUS_PRINT("[%s:%s:%d:unlock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); g_mutex_unlock(a); }; +#define janus_mutex_unlock_debug(a) { JANUS_PRINT("[%s:%s:%d:unlock] %p\n", __FILE__, __FUNCTION__, __LINE__, a); g_mutex_unlock(a); } /*! \brief Janus mutex unlock wrapper (selective locking debug) */ -#define janus_mutex_unlock(a) { if(!lock_debug) { janus_mutex_unlock_nodebug(a); } else { janus_mutex_unlock_debug(a); } }; +#define janus_mutex_unlock(a) { if(!lock_debug) { janus_mutex_unlock_nodebug(a); } else { janus_mutex_unlock_debug(a); } } /*! \brief Janus condition implementation */ typedef GCond janus_condition; diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 25c938c205..ceaa27f3aa 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -6489,14 +6489,18 @@ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp int asport = 0, asport_rtcp = 0; multiple_fds audio_fds = {-1, -1}; - if(g_atomic_int_get(&mp->destroyed)) { - curl_easy_cleanup(curl); - g_free(curldata->buffer); - g_free(curldata); - return -8; + while (!janus_mutex_trylock(&mountpoints_mutex)) { + if(g_atomic_int_get(&mp->destroyed)) { + JANUS_LOG(LOG_WARN, "[%s] Destroying mountpoint while trying to reconnect, aborting\n", mp->name); + curl_easy_cleanup(curl); + g_free(curldata->buffer); + g_free(curldata); + return -8; + } + + g_usleep(1000); } - janus_mutex_lock(&mountpoints_mutex); /* Parse both video and audio first before proceed to setup as curldata will be reused */ int vresult = -1; if(dovideo) {