summaryrefslogtreecommitdiff
path: root/include/asterisk/channel.h
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2013-12-19 17:45:21 +0000
committerMark Michelson <mmichelson@digium.com>2013-12-19 17:45:21 +0000
commit1b91ee6c4b636998381636fe23253558eafc9f13 (patch)
treeecb2487118d95d64f0946ff5acf29ceb566c6156 /include/asterisk/channel.h
parent3ccd5dee18dfbd64b01cba68790721680477df19 (diff)
Fix a deadlock that occurred due to a conflict of masquerades.
For the explanation, here is a copy-paste of the review board explanation: Initially, it was discovered that performing an attended transfer of a multiparty bridge with a PJSIP channel would cause a deadlock. A PBX thread started a masquerade and reached the point where it was calling the fixup() callback on the "original" channel. For chan_pjsip, this involves pushing a synchronous task to the session's serializer. The problem was that a task ahead of the fixup task was also attempting to perform a channel masquerade. However, since masquerades are designed in a way to only allow for one to occur at a time, the task ahead of the fixup could not continue until the masquerade already in progress had completed. And of course, the masquerade in progress could not complete until the task ahead of the fixup task had completed. Deadlock. The initial fix was to change the fixup task to be asynchronous. While this prevented the deadlock from occurring, it had the frightful side effect of potentially allowing for tasks in the session's serializer to operate on a zombie channel. Taking a step back from this particular deadlock, it became clear that the problem was not really this one particular issue but that masquerades themselves needed to be addressed. A PJSIP attended transfer operation calls ast_channel_move(), which attempts to both set up and execute a masquerade. The problem was that after it had set up the masquerade, the PBX thread had swooped in and tried to actually perform the masquerade. Looking at changes that had been made to Asterisk 12, it became clear that there never is any time now that anyone ever wants to set up a masquerade and allow for the channel thread to actually perform the masquerade. Everyone always is calling ast_channel_move(), performs the masquerade itself before returning. In this patch, I have removed all blocks of code from channel.c that will attempt to perform a masquerade if ast_channel_masq() returns true. Now, there is no distinction between setting up a masquerade and performing the masquerade. It is one operation. The only remaining checks for ast_channel_masq() and ast_channel_masqr() are in ast_hangup() since we do not want to interrupt a masquerade by hanging up the channel. Instead, now ast_hangup() will wait for a masquerade to complete before moving forward with its operation. The ast_channel_move() function has been modified to basically in-line the logic that used to be in ast_channel_masquerade(). ast_channel_masquerade() has been killed off for real. ast_channel_move() now has a lock associated with it that is used to prevent any simultaneous moves from occurring at once. This means there is no need to make sure that ast_channel_masq() or ast_channel_masqr() are already set on a channel when ast_channel_move() is called. It also means the channel container lock is not pulling double duty by both keeping the container locked and preventing multiple masquerades from occurring simultaneously. The ast_do_masquerade() function has been renamed to do_channel_masquerade() and is now internal to channel.c. The function now takes explicit arguments of which channels are involved in the masquerade instead of a single channel. While it probably is possible to do some further refactoring of this method, I feel that I would be treading dangerously. Instead, all I did was change some comments that no longer are true after this changeset. The other more minor change introduced in this patch is to res_pjsip.c to make ast_sip_push_task_synchronous() run the task in-place if we are already a SIP servant thread. This is related to this patch because even when we isolate the channel masquerade to only running in the SIP servant thread, we would still deadlock when the fixup() callback is reached since we would essentially be waiting forever for ourselves to finish before actually running the fixup. This makes it so the fixup is run without having to push a task into a serializer at all. (closes issue ASTERISK-22936) Reported by Jonathan Rose Review: https://reviewboard.asterisk.org/r/3069 ........ Merged revisions 404356 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404368 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'include/asterisk/channel.h')
-rw-r--r--include/asterisk/channel.h32
1 files changed, 0 insertions, 32 deletions
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 80ed7458c..5b042a96d 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -2014,26 +2014,6 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
/*!
- * \brief Weird function made for call transfers
- *
- * \param original channel to make a copy of
- * \param clone copy of the original channel
- *
- * \details
- * This is a very strange and freaky function used primarily for transfer. Suppose that
- * "original" and "clone" are two channels in random situations. This function takes
- * the guts out of "clone" and puts them into the "original" channel, then alerts the
- * channel driver of the change, asking it to fixup any private information (like the
- * p->owner pointer) that is affected by the change. The physical layer of the original
- * channel is hung up.
- *
- * \note Neither channel passed here should be locked before
- * calling this function. This function performs deadlock
- * avoidance involving these two channels.
- */
-int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
-
-/*!
* \brief Gives the string form of a given cause code.
*
* \param state cause to get the description of
@@ -2307,18 +2287,6 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v
int ast_transfer(struct ast_channel *chan, char *dest);
/*!
- * \brief Start masquerading a channel
- * \note absolutely _NO_ channel locks should be held before calling this function.
- * \details
- * XXX This is a seriously whacked out operation. We're essentially putting the guts of
- * the clone channel into the original channel. Start by killing off the original
- * channel's backend. I'm not sure we're going to keep this function, because
- * while the features are nice, the cost is very high in terms of pure nastiness. XXX
- * \param chan Channel to masquerade
- */
-void ast_do_masquerade(struct ast_channel *chan);
-
-/*!
* \brief Inherits channel variable from parent to child channel
* \param parent Parent channel
* \param child Child channel