[asterisk-dev] [Code Review] 2961: Add channel locking for calls that result in channel snapshot creation

Matt Jordan reviewboard at asterisk.org
Wed Oct 30 16:19:03 CDT 2013



> On Oct. 29, 2013, 11:08 p.m., rmudgett wrote:
> > /branches/12/main/pbx.c, lines 1569-1571
> > <https://reviewboard.asterisk.org/r/2961/diff/1/?file=47583#file47583line1569>
> >
> >     I do wonder about this functions channel snapshot.  The channel snapshot is updated when the app is executed but the snapshot is not restored when the app completes.  For normal dialplan execution, this is good.  For the other cases where an app is executed for miscellaneous reasons, maybe the channel should get a snapshot when the app is restored on exit of pbx_exec().
> 
> Matt Jordan wrote:
>     If you remove the channel snapshot here, you *will* break a lot of things. If you publish an additional snapshot here, you will also - most likely, anyway - break things as well, as the resetting of the application/data will make it look like the channel just re-entered that application. This occurs most frequently with Originated and Dialed channels - but will also screw up other channels that execute subroutines.
>     
>     If you decide to get adventurous and change this code, be prepared to have CDRs break in strange and creative ways.
> 
> rmudgett wrote:
>     The first snapshot in this function is necessary.  For normal dialplan execution, the app/data does not need to be restored because there shouldn't be any app/data so a second snapshot is not desireable.  For interception routines or applications that execute other applications, a second snapshot for the restoration of the app/data seems to be needed.
> 
> Matt Jordan wrote:
>     "For interception routines or applications that execute other applications, a second snapshot for the restoration of the app/data seems to be needed."
>     
>     It is not needed by any existing consumer of Stasis. In fact, 'restoring' the application after an intercept routine runs complicates and confuses a consumer's view of the world.
>     
>     Say I'm a consumer of Stasis, watching messages about SIP/foo, and I care about what application SIP/foo happens to be in. When SIP/foo enters into an application, I make some logical decisions in my application.
>     
>     Let's say I get the following application + CEP changes:
>     
>     default,1234,1: NoOp
>     default,1234,2: Dial
>     default,my_routine,1: NoOp
>     default,my_routine,2: CONNECTEDLINE
>     default,my_routine,3: Return
>     default,1234,2: Dial
>     
>     By re-sending the Dial application, you've required consumers of Stasis to maintain their own program counter for each channel so that they 'know' whether or not the second Dial application that they see is the same Dial application the channel was already in, or the existing Dial application. They have to "know" how Subroutine execution works, as well as Macro execution. You've increased the complexity and the difficulty of each consumer in maintaining application state.
>     
>     If you don't send the second Dial, you do run the risk that the consumers don't 'know' when the channel returns into the Dial application. Thus far, that has been by far the lesser of these two evils. I do not advocate making this change unless there is an absolute clear necessity for it.
> 
> rmudgett wrote:
>     Regardless of a second snapshot being taken or not by this routine, if a channel snapshot is taken later for whatever reason, the app/data has been restored.

In practice, this hasn't been a problem. Things that go off and execute subroutines have not been issuing additional snapshots immediately thereafter. If this becomes a problem then it's worthwhile to revisit this; otherwise, changing this behavior merely on speculative reasons feels like it will create huge problems with little to no benefit.


- Matt


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviewboard.asterisk.org/r/2961/#review10031
-----------------------------------------------------------


On Oct. 25, 2013, 5:07 p.m., Mark Michelson wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://reviewboard.asterisk.org/r/2961/
> -----------------------------------------------------------
> 
> (Updated Oct. 25, 2013, 5:07 p.m.)
> 
> 
> Review request for Asterisk Developers.
> 
> 
> Bugs: ASTERISK-22709
>     https://issues.asterisk.org/jira/browse/ASTERISK-22709
> 
> 
> Repository: Asterisk
> 
> 
> Description
> -------
> 
> John Bigelow discovered that if the newly-created atxfer_threeway_nominal test is run in a loop, eventually a test run will cause the UUT instance of Asterisk to crash. Investigation of the crash showed that the crash was being caused while trying to get the string representation of a channel's translation paths while creating a channel snapshot. The attended transfer manager thread was creating the channel snapshot as part of the attended transfer stasis message while in another thread (in this case, the bridge channel thread) the translation paths were being altered to make the channel compatible with others in the bridge.
> 
> It's clear that the issue is that the channel's contents are not lock protected while creating a channel snapshot. Luckily, the channel's lock is held already when updating translation paths. By adding locking, I was able to run the test over 450 times straight with no negative consequences.
> 
> When adding locking, there were two strategies to follow:
> 
> 1) Take advantage of the fact that channel locks are recursive, and just add a single SCOPED_CHANNELLOCK() call to ast_channel_snapshot_create() and call it a day.
> 2) Make an audit of channel-related calls that end up creating a channel snapshot and require locks be held prior to making those calls.
> 
> I like approach 2 more, even though it's harder to pull off. In investigating what paths result in channel snapshots being created, I found that channel locks should be required before calling the following functions:
> 
> * ast_channel_snapshot_create()
> * ast_channel_blob_create()
> * ast_channel_publish_snapshot()
> * ast_publish_channel_state()
> * ast_channel_publish_blob()
> * ast_channel_publish_varset()
> * ast_channel_amaflags_set()
> * ast_channel_callid_set()
> * ast_channel_whentohangup_set()
> * ast_channel_callgroup_set()
> * ast_channel_pickupgroup_set()
> * ast_channel_internal_bridge_set()
> * ast_channel_language_set()
> * ast_channel_accountcode_set()
> * ast_channel_peeraccount_set()
> * ast_channel_linkedid_set()
> * ast_channel_stage_snapshot()
> * ast_setstate()
> * ast_aoc_manager_event()
> * ast_channel_setwhentohangup_tv()
> * ast_channel_setwhentohangup()
> * ast_set_variables()
> 
> All of these functions' documentation have been updated to indicate a precondition of having the channel locked.
> 
> In addition, there are some more complex functions that create channel snapshots but could not easily be made to have the precondition of having the channel locked. These are:
> 
> * ast_bridge_blob_create()
> * ast_publish_attended_transfer_fail()
> * ast_publish_attended_transfer_bridge_merge()
> * ast_publish_attended_transfer_threeway()
> * ast_publish_attended_transfer_app()
> * ast_publish_attended_transfer_link()
> * ast_bridge_publish_enter()
> * ast_bridge_publish_leave()
> * ast_bridge_publish_blind_transfer()
> 
> These functions' documentation now have a precondition of having no channels or bridges locked.
> 
> This review seeks only to make sure that channels are properly locked prior to creating channel snapshots. A similar effort is likely needed to ensure that bridges are locked during bridge snapshot creation.
> 
> 
> Diffs
> -----
> 
>   /branches/12/tests/test_stasis_channels.c 401703 
>   /branches/12/tests/test_cel.c 401703 
>   /branches/12/tests/test_cdr.c 401703 
>   /branches/12/res/res_stasis.c 401703 
>   /branches/12/res/res_pjsip_refer.c 401703 
>   /branches/12/res/res_agi.c 401703 
>   /branches/12/res/parking/parking_manager.c 401703 
>   /branches/12/res/parking/parking_bridge_features.c 401703 
>   /branches/12/res/ari/resource_bridges.c 401703 
>   /branches/12/pbx/pbx_realtime.c 401703 
>   /branches/12/main/stasis_channels.c 401703 
>   /branches/12/main/stasis_bridges.c 401703 
>   /branches/12/main/pickup.c 401703 
>   /branches/12/main/pbx.c 401703 
>   /branches/12/main/endpoints.c 401703 
>   /branches/12/main/dial.c 401703 
>   /branches/12/main/core_unreal.c 401703 
>   /branches/12/main/core_local.c 401703 
>   /branches/12/main/channel.c 401703 
>   /branches/12/main/cel.c 401703 
>   /branches/12/main/bridge_channel.c 401703 
>   /branches/12/main/bridge.c 401703 
>   /branches/12/include/asterisk/stasis_channels.h 401703 
>   /branches/12/include/asterisk/stasis_bridges.h 401703 
>   /branches/12/include/asterisk/channelstate.h 401703 
>   /branches/12/include/asterisk/channel.h 401703 
>   /branches/12/include/asterisk/aoc.h 401703 
>   /branches/12/funcs/func_timeout.c 401703 
>   /branches/12/channels/sig_pri.c 401703 
>   /branches/12/channels/sig_analog.c 401703 
>   /branches/12/channels/chan_vpb.cc 401703 
>   /branches/12/channels/chan_unistim.c 401703 
>   /branches/12/channels/chan_skinny.c 401703 
>   /branches/12/channels/chan_sip.c 401703 
>   /branches/12/channels/chan_pjsip.c 401703 
>   /branches/12/channels/chan_phone.c 401703 
>   /branches/12/channels/chan_oss.c 401703 
>   /branches/12/channels/chan_nbs.c 401703 
>   /branches/12/channels/chan_motif.c 401703 
>   /branches/12/channels/chan_misdn.c 401703 
>   /branches/12/channels/chan_mgcp.c 401703 
>   /branches/12/channels/chan_jingle.c 401703 
>   /branches/12/channels/chan_iax2.c 401703 
>   /branches/12/channels/chan_h323.c 401703 
>   /branches/12/channels/chan_gtalk.c 401703 
>   /branches/12/channels/chan_dahdi.c 401703 
>   /branches/12/channels/chan_console.c 401703 
>   /branches/12/channels/chan_alsa.c 401703 
>   /branches/12/apps/app_voicemail.c 401703 
>   /branches/12/apps/app_userevent.c 401703 
>   /branches/12/apps/app_queue.c 401703 
>   /branches/12/apps/app_meetme.c 401703 
>   /branches/12/apps/app_disa.c 401703 
>   /branches/12/apps/app_dial.c 401703 
>   /branches/12/apps/app_confbridge.c 401703 
>   /branches/12/apps/app_agent_pool.c 401703 
>   /branches/12/addons/chan_ooh323.c 401703 
>   /branches/12/addons/chan_mobile.c 401703 
> 
> Diff: https://reviewboard.asterisk.org/r/2961/diff/
> 
> 
> Testing
> -------
> 
> As stated in the description, I ran the atxfer_threeway_nominal test in a loop. After approximately 450 test runs, there were no negative consequences. Prior to this changeset, running the test 20-50 times would result in a crash.
> 
> 
> Thanks,
> 
> Mark Michelson
> 
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-dev/attachments/20131030/6848f10e/attachment-0001.html>


More information about the asterisk-dev mailing list