diff options
author | Richard Mudgett <rmudgett@digium.com> | 2015-03-06 19:34:35 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2015-03-06 19:34:35 +0000 |
commit | f1ab2c5e8b77473b76391bbdc2bf5b12f32f0372 (patch) | |
tree | 7434d13c134564f959f1a0b6378067c122734ff5 | |
parent | 5c3e33b3ca5a726162745c4fb5435d98f737a3b7 (diff) |
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
-rw-r--r-- | channels/chan_sip.c | 68 |
1 files changed, 49 insertions, 19 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cf2cd097c..13c55462c 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")); } } |