summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2015-06-20 21:38:02 -0300
committerJoshua Colp <jcolp@digium.com>2015-06-20 19:48:34 -0500
commit5caefc98a1928c2aa21c1e820803a8af23f0a4b3 (patch)
treea37cc9361e3b6b8f6346d07e826fc9a767e3849b
parentbd77ace25aace29c5936458b702146fc1b0288a1 (diff)
chan_sip: Destroy peers without holding peers container lock.
Due to the use of stasis_unsubscribe_and_join in the peer destructor it is possible for a deadlock to occur when an event callback is occurring at the same time. This happens because the peer may be destroyed while holding the peers container lock. If this occurs the event callback will never be able to acquire the container lock and the unsubscribe will never complete. This change makes it so the peers that have been removed from the peers container are not destroyed with the container lock held. ASTERISK-25163 #close Change-Id: Ic6bf1d9da4310142a4d196c45ddefb99317d9a33
-rw-r--r--channels/chan_sip.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 4112e00a3..b29bcdc05 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -3179,10 +3179,24 @@ static int match_and_cleanup_peer_sched(void *peerobj, void *arg, int flags)
static void unlink_peers_from_tables(peer_unlink_flag_t flag)
{
- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
+ struct ao2_iterator *peers_iter;
+
+ /*
+ * We must remove the ref outside of the peers container to prevent
+ * a deadlock condition when unsubscribing from stasis while it is
+ * invoking a subscription event callback.
+ */
+ peers_iter = ao2_t_callback(peers, OBJ_UNLINK | OBJ_MULTIPLE,
match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers");
- ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
+ if (peers_iter) {
+ ao2_iterator_destroy(peers_iter);
+ }
+
+ peers_iter = ao2_t_callback(peers_by_ip, OBJ_UNLINK | OBJ_MULTIPLE,
match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers_by_ip");
+ if (peers_iter) {
+ ao2_iterator_destroy(peers_iter);
+ }
}
/* \brief Unlink all marked peers from ao2 containers */