From f1ab2c5e8b77473b76391bbdc2bf5b12f32f0372 Mon Sep 17 00:00:00 2001 From: Richard Mudgett <rmudgett@digium.com> Date: Fri, 6 Mar 2015 19:34:35 +0000 Subject: [PATCH] chan_sip: Fix realtime locking inversion when poking a just built peer. When a realtime peer is built it can cause a locking inversion when the just built peer is poked. If the CLI command "sip show channels" is periodically executed then a deadlock can happen because of the locking inversion. * Push the peer poke off onto the scheduler thread to avoid the locking inversion of the just built realtime peer. AST-1540 ASTERISK-24838 #close Reported by: Richard Mudgett Review: https://reviewboard.asterisk.org/r/4454/ ........ Merged revisions 432526 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 432528 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@432529 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_sip.c | 68 ++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cf2cd097c3..13c55462c6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -16020,6 +16020,17 @@ static int sip_poke_peer_s(const void *data) return 0; } +static int sip_poke_peer_now(const void *data) +{ + struct sip_peer *peer = (struct sip_peer *) data; + + peer->pokeexpire = -1; + sip_poke_peer(peer, 0); + sip_unref_peer(peer, "removing poke peer ref"); + + return 0; +} + /*! \brief Get registration details from Asterisk DB */ static void reg_source_db(struct sip_peer *peer) { @@ -20697,24 +20708,33 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ast_str *cbuf; - struct ast_cb_names cbnames = {9, { "retrans_pkt", - "__sip_autodestruct", - "expire_register", - "auto_congest", - "sip_reg_timeout", - "sip_poke_peer_s", - "sip_poke_noanswer", - "sip_reregister", - "sip_reinvite_retry"}, - { retrans_pkt, - __sip_autodestruct, - expire_register, - auto_congest, - sip_reg_timeout, - sip_poke_peer_s, - sip_poke_noanswer, - sip_reregister, - sip_reinvite_retry}}; + struct ast_cb_names cbnames = { + 10, + { + "retrans_pkt", + "__sip_autodestruct", + "expire_register", + "auto_congest", + "sip_reg_timeout", + "sip_poke_peer_s", + "sip_poke_peer_now", + "sip_poke_noanswer", + "sip_reregister", + "sip_reinvite_retry" + }, + { + retrans_pkt, + __sip_autodestruct, + expire_register, + auto_congest, + sip_reg_timeout, + sip_poke_peer_s, + sip_poke_peer_now, + sip_poke_noanswer, + sip_reregister, + sip_reinvite_retry + } + }; switch (cmd) { case CLI_INIT: @@ -31102,7 +31122,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str /* Startup regular pokes */ if (!devstate_only && enablepoke) { - sip_poke_peer(peer, 0); + /* + * We cannot poke the peer now in this thread without + * a lock inversion so pass it off to the scheduler + * thread. + */ + AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, + 0, /* Poke the peer ASAP */ + sip_poke_peer_now, peer, + sip_unref_peer(_data, "removing poke peer ref"), + sip_unref_peer(peer, "removing poke peer ref"), + sip_ref_peer(peer, "adding poke peer ref")); } } -- GitLab