[asterisk-commits] kmoore: branch kmoore/stasis-bridging-channel_events r385337 - in /team/kmoor...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Apr 11 12:35:26 CDT 2013


Author: kmoore
Date: Thu Apr 11 12:35:22 2013
New Revision: 385337

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385337
Log:
Multiple revisions 385272,385279,385296,385317

........
  r385272 | rmudgett | 2013-04-10 17:14:14 -0500 (Wed, 10 Apr 2013) | 11 lines
  
  confbridge: Fix announcer channel bridge depart getting stuck.
  
  When the announcer channel needs to depart from the bridge, the thread
  needs to be poked to get it out of an indefinite wait for media.  More
  generally, the bridge channel thread needs to be poked whenever it is in
  the normal bridge_channel_wait()'s ast_waitfor_nandfds() call and the
  state changes.
  
  * Fixes the small window of opportunity in bridge_channel_wait() when
  entering ast_waitfor_nandfds().
........
  r385279 | root | 2013-04-10 18:17:19 -0500 (Wed, 10 Apr 2013) | 25 lines
  
  Multiple revisions 385277-385278
  
  ........
    r385277 | rmudgett | 2013-04-10 18:03:30 -0500 (Wed, 10 Apr 2013) | 13 lines
    
    * Fix unlocked accesses to feature_list.  The feature_list is now also
    protected by the features_lock.
    
    * Made all calls to ast_find_call_feature() have the features_lock held.
    
    * Fixed set_config_flags() to actually use find_group() to look for
    feature groups in DYNAMIC_FEATURES.  The code originally assumed all
    feature groups were listed in DYNAMIC_FEATURES.
    
    * Make everyone use ast_rdlock_call_features(),
    ast_unlock_call_features(), and new ast_wrlock_call_features() instead of
    directly calling the rwlock API on features_lock.
  ........
    r385278 | rmudgett | 2013-04-10 18:08:02 -0500 (Wed, 10 Apr 2013) | 1 line
    
    Eliminated dial_features_destroy() since it is equivalent to ast_free_ptr()
  ........
  
  Merged revisions 385277-385278 from file:///srv/subversion/repos/asterisk/trunk
........
  r385296 | rmudgett | 2013-04-10 18:37:01 -0500 (Wed, 10 Apr 2013) | 14 lines
  
  * Make ast_bridge_impart() allocate a features struct if one is not
  provided.
  
  * Make ast_bridge_join() exit early if a features struct is not provided.
  Later when ast_bridge_join() is changed to require the features struct to
  be allocated we can allocate one like ast_bridge_impart().
  
  * Fix ConfBridge recording channel to supply a features structure when it
  joins the bridge.
  
  * Make the application running on a bridge channel break the bridge if it
  returns non-zero like the old bridge code.  An application is supposed to
  return non-zero if the channel hangs up.
........
  r385317 | root | 2013-04-11 12:17:20 -0500 (Thu, 11 Apr 2013) | 8 lines
  
  Fix 'pri intense debug span' alias.
  ........
  
  Merged revisions 385313 from http://svn.asterisk.org/svn/asterisk/branches/11
  ........
  
  Merged revisions 385314 from file:///srv/subversion/repos/asterisk/trunk
........

Merged revisions 385272,385279,385296,385317 from http://svn.asterisk.org/svn/asterisk/team/group/bridge_construction

Modified:
    team/kmoore/stasis-bridging-channel_events/   (props changed)
    team/kmoore/stasis-bridging-channel_events/apps/app_confbridge.c
    team/kmoore/stasis-bridging-channel_events/configs/cli_aliases.conf.sample
    team/kmoore/stasis-bridging-channel_events/include/asterisk/bridging.h
    team/kmoore/stasis-bridging-channel_events/main/bridging.c
    team/kmoore/stasis-bridging-channel_events/main/features.c
    team/kmoore/stasis-bridging-channel_events/main/manager.c

Propchange: team/kmoore/stasis-bridging-channel_events/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/kmoore/stasis-bridging-channel_events/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Apr 11 12:35:22 2013
@@ -1,1 +1,1 @@
-/team/group/bridge_construction:1-385264
+/team/group/bridge_construction:1-385336

Modified: team/kmoore/stasis-bridging-channel_events/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-bridging-channel_events/apps/app_confbridge.c?view=diff&rev=385337&r1=385336&r2=385337
==============================================================================
--- team/kmoore/stasis-bridging-channel_events/apps/app_confbridge.c (original)
+++ team/kmoore/stasis-bridging-channel_events/apps/app_confbridge.c Thu Apr 11 12:35:22 2013
@@ -649,6 +649,7 @@
 	struct ast_channel *chan;
 	struct ast_str *filename = ast_str_alloca(PATH_MAX);
 	struct ast_str *orig_rec_file = NULL;
+	struct ast_bridge_features features;
 
 	ast_mutex_lock(&conference->record_lock);
 	if (!mixmonapp) {
@@ -658,20 +659,27 @@
 		ao2_ref(conference, -1);
 		return NULL;
 	}
+	if (ast_bridge_features_init(&features)) {
+		conference->record_thread = AST_PTHREADT_NULL;
+		ast_mutex_unlock(&conference->record_lock);
+		ao2_ref(conference, -1);
+		return NULL;
+	}
 
 	/* XXX If we get an EXIT right here, START will essentially be a no-op */
 	while (conference->record_state != CONF_RECORD_EXIT) {
 		set_rec_filename(conference, &filename,
-				 is_new_rec_file(conference->b_profile.rec_file, &orig_rec_file));
+			is_new_rec_file(conference->b_profile.rec_file, &orig_rec_file));
 		chan = ast_channel_ref(conference->record_chan);
 		ast_answer(chan);
 		pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
-		ast_bridge_join(conference->bridge, chan, NULL, NULL, NULL, 0);
+		ast_bridge_join(conference->bridge, chan, NULL, &features, NULL, 0);
 
 		ast_hangup(chan); /* This will eat this thread's reference to the channel as well */
 		/* STOP has been called. Wait for either a START or an EXIT */
 		ast_cond_wait(&conference->record_cond, &conference->record_lock);
 	}
+	ast_bridge_features_cleanup(&features);
 	ast_free(orig_rec_file);
 	ast_mutex_unlock(&conference->record_lock);
 	ao2_ref(conference, -1);

Modified: team/kmoore/stasis-bridging-channel_events/configs/cli_aliases.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-bridging-channel_events/configs/cli_aliases.conf.sample?view=diff&rev=385337&r1=385336&r2=385337
==============================================================================
--- team/kmoore/stasis-bridging-channel_events/configs/cli_aliases.conf.sample (original)
+++ team/kmoore/stasis-bridging-channel_events/configs/cli_aliases.conf.sample Thu Apr 11 12:35:22 2013
@@ -26,7 +26,7 @@
 hangup request=channel request hangup
 originate=channel originate
 help=core show help
-pri intense debug span=pri set debug 2 span
+pri intense debug span=pri set debug intense span
 reload=module reload
 
 ; CLI Alias Templates

Modified: team/kmoore/stasis-bridging-channel_events/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-bridging-channel_events/include/asterisk/bridging.h?view=diff&rev=385337&r1=385336&r2=385337
==============================================================================
--- team/kmoore/stasis-bridging-channel_events/include/asterisk/bridging.h (original)
+++ team/kmoore/stasis-bridging-channel_events/include/asterisk/bridging.h Thu Apr 11 12:35:22 2013
@@ -177,6 +177,8 @@
 	AST_LIST_HEAD_NOLOCK(, ast_frame) wr_queue;
 	/*! Pipe to alert thread when frames are put into the wr_queue. */
 	int alert_pipe[2];
+	/*! TRUE if the bridge channel thread is waiting on channels (needs to be atomically settable) */
+	int waiting;
 };
 
 enum ast_bridge_action_type {

Modified: team/kmoore/stasis-bridging-channel_events/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-bridging-channel_events/main/bridging.c?view=diff&rev=385337&r1=385336&r2=385337
==============================================================================
--- team/kmoore/stasis-bridging-channel_events/main/bridging.c (original)
+++ team/kmoore/stasis-bridging-channel_events/main/bridging.c Thu Apr 11 12:35:22 2013
@@ -221,8 +221,10 @@
 static void bridge_channel_poke(struct ast_bridge_channel *bridge_channel)
 {
 	if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
-		pthread_kill(bridge_channel->thread, SIGURG);
-		ast_cond_signal(&bridge_channel->cond);
+		while (bridge_channel->waiting) {
+			pthread_kill(bridge_channel->thread, SIGURG);
+			sched_yield();
+		}
 	}
 }
 
@@ -239,6 +241,8 @@
 
 	/* Change the state on the bridge channel */
 	bridge_channel->state = new_state;
+
+	bridge_channel_poke(bridge_channel);
 }
 
 void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
@@ -568,6 +572,7 @@
 	}
 
 /* BUGBUG the feature hook matching needs to be done here.  Any matching feature hook needs to be queued onto the bridge_channel.  Also the feature hook digit timeout needs to be handled. */
+/* BUGBUG the AMI atxfer action just sends DTMF end events to initiate DTMF atxfer and dial the extension.  Another reason the DTMF hook matching needs rework. */
 	/* See if this DTMF matches the beginnings of any feature hooks, if so we switch to the feature state to either execute the feature or collect more DTMF */
 	dtmf[0] = frame->subclass.integer;
 	dtmf[1] = '\0';
@@ -685,8 +690,10 @@
 	bridge_channel_write_frame(bridge_channel, &frame);
 }
 
-static void run_app_helper(struct ast_channel *chan, const char *app_name, const char *app_args)
-{
+static int run_app_helper(struct ast_channel *chan, const char *app_name, const char *app_args)
+{
+	int res = 0;
+
 	if (!strcasecmp("Gosub", app_name)) {
 		ast_app_exec_sub(NULL, chan, app_args, 0);
 	} else if (!strcasecmp("Macro", app_name)) {
@@ -698,9 +705,10 @@
 		if (!app) {
 			ast_log(LOG_WARNING, "Could not find application (%s)\n", app_name);
 		} else {
-			pbx_exec(chan, app, app_args);
-		}
-	}
+			res = pbx_exec(chan, app, app_args);
+		}
+	}
+	return res;
 }
 
 void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
@@ -714,7 +722,10 @@
 				moh_class, strlen(moh_class) + 1);
 		}
 	}
-	run_app_helper(bridge_channel->chan, app_name, S_OR(app_args, ""));
+	if (run_app_helper(bridge_channel->chan, app_name, S_OR(app_args, ""))) {
+		/* Break the bridge if the app returns non-zero. */
+		bridge_handle_hangup(bridge_channel);
+	}
 	if (moh_class) {
 		ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD,
 			NULL, 0);
@@ -722,7 +733,7 @@
 }
 
 struct bridge_run_app {
-	/*! Offset into app_name[] where the MOH class name starts.  (zero if no MOH)*/
+	/*! Offset into app_name[] where the MOH class name starts.  (zero if no MOH) */
 	int moh_offset;
 	/*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */
 	int app_args_offset;
@@ -2145,11 +2156,13 @@
 		ast_debug(10, "Bridge %s: %p(%s) is going into a waitfor\n",
 			bridge_channel->bridge->uniqueid, bridge_channel,
 			ast_channel_name(bridge_channel->chan));
+		bridge_channel->waiting = 1;
 		ast_bridge_channel_unlock(bridge_channel);
 		outfd = -1;
 /* BUGBUG need to make the next expiring active interval setup ms timeout rather than holding up the chan reads. */
 		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1,
 			&bridge_channel->alert_pipe[0], 1, NULL, &outfd, &ms);
+		bridge_channel->waiting = 0;
 		if (!bridge_channel->suspended
 			&& bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
 			if (chan) {
@@ -2761,6 +2774,13 @@
 		state = AST_BRIDGE_CHANNEL_STATE_HANGUP;
 		goto join_exit;
 	}
+/* BUGBUG features cannot be NULL when passed in. When it is changed to allocated we can do like ast_bridge_impart() and allocate one. */
+	ast_assert(features != NULL);
+	if (!features) {
+		ao2_ref(bridge_channel, -1);
+		state = AST_BRIDGE_CHANNEL_STATE_HANGUP;
+		goto join_exit;
+	}
 	if (tech_args) {
 		bridge_channel->tech_args = *tech_args;
 	}
@@ -2863,9 +2883,18 @@
 	int res;
 	struct ast_bridge_channel *bridge_channel;
 
+	/* Supply an empty features structure if the caller did not. */
+	if (!features) {
+		features = ast_bridge_features_new();
+		if (!features) {
+			return -1;
+		}
+	}
+
 	/* Try to allocate a structure for the bridge channel */
 	bridge_channel = bridge_channel_alloc(bridge);
 	if (!bridge_channel) {
+		ast_bridge_features_destroy(features);
 		return -1;
 	}
 
@@ -2941,17 +2970,7 @@
 
 	/* We are claiming the reference held by the depart thread. */
 
-	ast_bridge_channel_lock(bridge_channel);
-	ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
-
-/* BUGBUG hack alert ast_bridge_depart() may fail to return because of a race condition. */
-	/*
-	 * XXX The poke is a bit of a hack since there is a race
-	 * condition in bridge_channel_wait() when it is just about to
-	 * enter ast_waitfor_nandfds() and we poke the thread.
-	 */
-	bridge_channel_poke(bridge_channel);
-	ast_bridge_channel_unlock(bridge_channel);
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
 
 	/* Wait for the depart thread to die */
 	ast_debug(1, "Waiting for %p(%s) bridge thread to die.\n",

Modified: team/kmoore/stasis-bridging-channel_events/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-bridging-channel_events/main/features.c?view=diff&rev=385337&r1=385336&r2=385337
==============================================================================
--- team/kmoore/stasis-bridging-channel_events/main/features.c (original)
+++ team/kmoore/stasis-bridging-channel_events/main/features.c Thu Apr 11 12:35:22 2013
@@ -880,17 +880,9 @@
 	return df_copy;
 }
 
-static void dial_features_destroy(void *data)
-{
-	struct ast_dial_features *df = data;
-	if (df) {
-		ast_free(df);
-	}
-}
-
 static const struct ast_datastore_info dial_features_info = {
 	.type = "dial-features",
-	.destroy = dial_features_destroy,
+	.destroy = ast_free_ptr,
 	.duplicate = dial_features_duplicate,
 };
 
@@ -3075,6 +3067,25 @@
 
 AST_RWLOCK_DEFINE_STATIC(features_lock);
 
+/*! \note This is protected by features_lock. */
+static AST_LIST_HEAD_NOLOCK_STATIC(feature_list, ast_call_feature);
+
+static void ast_wrlock_call_features(void)
+{
+	ast_rwlock_wrlock(&features_lock);
+}
+
+void ast_rdlock_call_features(void)
+{
+	ast_rwlock_rdlock(&features_lock);
+}
+
+void ast_unlock_call_features(void)
+{
+	ast_rwlock_unlock(&features_lock);
+}
+
+/*! \note This is protected by features_lock. */
 static struct ast_call_feature builtin_features[] = {
 	{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
 	{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
@@ -3084,10 +3095,7 @@
 	{ AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
 };
 
-
-static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
-
-/*! \brief register new feature into feature_list*/
+/*! \brief register new feature into feature_list */
 void ast_register_feature(struct ast_call_feature *feature)
 {
 	if (!feature) {
@@ -3095,9 +3103,9 @@
 		return;
 	}
 
-	AST_RWLIST_WRLOCK(&feature_list);
-	AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
-	AST_RWLIST_UNLOCK(&feature_list);
+	ast_wrlock_call_features();
+	AST_LIST_INSERT_HEAD(&feature_list, feature, feature_entry);
+	ast_unlock_call_features();
 
 	ast_verb(2, "Registered Feature '%s'\n",feature->sname);
 }
@@ -3174,9 +3182,9 @@
 		return;
 	}
 
-	AST_RWLIST_WRLOCK(&feature_list);
-	AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
-	AST_RWLIST_UNLOCK(&feature_list);
+	ast_wrlock_call_features();
+	AST_LIST_REMOVE(&feature_list, feature, feature_entry);
+	ast_unlock_call_features();
 
 	ast_free(feature);
 }
@@ -3186,19 +3194,23 @@
 {
 	struct ast_call_feature *feature;
 
-	AST_RWLIST_WRLOCK(&feature_list);
-	while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
+	ast_wrlock_call_features();
+	while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
 		ast_free(feature);
 	}
-	AST_RWLIST_UNLOCK(&feature_list);
-}
-
-/*! \brief find a call feature by name */
+	ast_unlock_call_features();
+}
+
+/*!
+ * \internal
+ * \brief find a dynamic call feature by name
+ * \pre Expects features_lock to be at least readlocked
+ */
 static struct ast_call_feature *find_dynamic_feature(const char *name)
 {
 	struct ast_call_feature *tmp;
 
-	AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
+	AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
 		if (!strcasecmp(tmp->sname, name)) {
 			break;
 		}
@@ -3244,19 +3256,9 @@
 	return fg;
 }
 
-void ast_rdlock_call_features(void)
-{
-	ast_rwlock_rdlock(&features_lock);
-}
-
-void ast_unlock_call_features(void)
-{
-	ast_rwlock_unlock(&features_lock);
-}
-
 /*!
  * \internal
- * \pre Expects feature_lock to be readlocked
+ * \pre Expects features_lock to be at least readlocked
  */
 struct ast_call_feature *ast_find_call_feature(const char *name)
 {
@@ -3402,7 +3404,7 @@
  * \internal
  * \brief Get the extension for a given builtin feature
  *
- * \pre expects feature_lock to be readlocked
+ * \pre expects features_lock to be readlocked
  *
  * \retval 0 success
  * \retval non-zero failiure
@@ -3519,17 +3521,17 @@
 {
 	int x;
 
-	ast_rwlock_wrlock(&features_lock);
+	ast_wrlock_call_features();
 	for (x = 0; x < FEATURES_COUNT; x++)
 		strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
-	ast_rwlock_unlock(&features_lock);
+	ast_unlock_call_features();
 }
 
 static int remap_feature(const char *name, const char *value)
 {
 	int x, res = -1;
 
-	ast_rwlock_wrlock(&features_lock);
+	ast_wrlock_call_features();
 	for (x = 0; x < FEATURES_COUNT; x++) {
 		if (strcasecmp(builtin_features[x].sname, name))
 			continue;
@@ -3538,7 +3540,7 @@
 		res = 0;
 		break;
 	}
-	ast_rwlock_unlock(&features_lock);
+	ast_unlock_call_features();
 
 	return res;
 }
@@ -3569,7 +3571,7 @@
 		return -1; /* can not run feature operation */
 	}
 
-	ast_rwlock_rdlock(&features_lock);
+	ast_rdlock_call_features();
 	for (x = 0; x < FEATURES_COUNT; x++) {
 		char feature_exten[FEATURE_MAX_LEN] = "";
 
@@ -3611,7 +3613,7 @@
 				"Result: fail");
 	}
 
-	ast_rwlock_unlock(&features_lock);
+	ast_unlock_call_features();
 
 	if (!dynamic_features_buf || !ast_str_strlen(dynamic_features_buf) || feature_detected) {
 		return res;
@@ -3621,9 +3623,7 @@
 
 	while ((tok = strsep(&tmp, "#"))) {
 		AST_RWLIST_RDLOCK(&feature_groups);
-
 		fg = find_group(tok);
-
 		if (fg) {
 			AST_LIST_TRAVERSE(&fg->features, fge, entry) {
 				if (!strcmp(fge->exten, code)) {
@@ -3646,13 +3646,12 @@
 				break;
 			}
 		}
-
 		AST_RWLIST_UNLOCK(&feature_groups);
 
-		AST_RWLIST_RDLOCK(&feature_list);
+		ast_rdlock_call_features();
 
 		if (!(tmpfeature = find_dynamic_feature(tok))) {
-			AST_RWLIST_UNLOCK(&feature_list);
+			ast_unlock_call_features();
 			continue;
 		}
 
@@ -3668,14 +3667,14 @@
 				memcpy(feature, tmpfeature, sizeof(*feature));
 			}
 			if (res != AST_FEATURE_RETURN_KEEPTRYING) {
-				AST_RWLIST_UNLOCK(&feature_list);
+				ast_unlock_call_features();
 				break;
 			}
 			res = AST_FEATURE_RETURN_PASSDIGITS;
 		} else if (!strncmp(tmpfeature->exten, code, strlen(code)))
 			res = AST_FEATURE_RETURN_STOREDIGITS;
 
-		AST_RWLIST_UNLOCK(&feature_list);
+		ast_unlock_call_features();
 	}
 
 	return res;
@@ -3762,7 +3761,7 @@
 
 	ast_clear_flag(config, AST_FLAGS_ALL);
 
-	ast_rwlock_rdlock(&features_lock);
+	ast_rdlock_call_features();
 	for (x = 0; x < FEATURES_COUNT; x++) {
 		if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
 			continue;
@@ -3773,7 +3772,7 @@
 		if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
 			ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
 	}
-	ast_rwlock_unlock(&features_lock);
+	ast_unlock_call_features();
 
 	if (!(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
 		const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
@@ -3788,7 +3787,8 @@
 				struct feature_group *fg;
 
 				AST_RWLIST_RDLOCK(&feature_groups);
-				AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
+				fg = find_group(tok);
+				if (fg) {
 					struct feature_group_exten *fge;
 
 					AST_LIST_TRAVERSE(&fg->features, fge, entry) {
@@ -3802,7 +3802,7 @@
 				}
 				AST_RWLIST_UNLOCK(&feature_groups);
 
-				AST_RWLIST_RDLOCK(&feature_list);
+				ast_rdlock_call_features();
 				if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
 					if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
 						ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
@@ -3811,7 +3811,7 @@
 						ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
 					}
 				}
-				AST_RWLIST_UNLOCK(&feature_list);
+				ast_unlock_call_features();
 			}
 		}
 	}
@@ -3927,7 +3927,7 @@
 	}
 
 	/* support dialing of the featuremap disconnect code while performing an attended tranfer */
-	ast_rwlock_rdlock(&features_lock);
+	ast_rdlock_call_features();
 	for (x = 0; x < FEATURES_COUNT; x++) {
 		if (strcasecmp(builtin_features[x].sname, "disconnect"))
 			continue;
@@ -3938,7 +3938,7 @@
 		memset(dialed_code, 0, len);
 		break;
 	}
-	ast_rwlock_unlock(&features_lock);
+	ast_unlock_call_features();
 	x = 0;
 	started = ast_tvnow();
 	to = timeout;
@@ -4341,7 +4341,6 @@
 #else
 	return 0;
 #endif
-/* BUGBUG dynamic features not handled yet.  App run returns non-zero breaks bridge and ast_bridge_call returns 0.  App returns zero continues bridge. */
 }
 
 static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
@@ -5839,14 +5838,14 @@
 		return;
 	}
 
-	AST_RWLIST_RDLOCK(&feature_list);
+	ast_rdlock_call_features();
 	if (find_dynamic_feature(var->name)) {
-		AST_RWLIST_UNLOCK(&feature_list);
+		ast_unlock_call_features();
 		ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
 			var->name);
 		return;
 	}
-	AST_RWLIST_UNLOCK(&feature_list);
+	ast_unlock_call_features();
 
 	if (!(feature = ast_calloc(1, sizeof(*feature)))) {
 		return;
@@ -6048,14 +6047,13 @@
 		for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
 			struct ast_call_feature *feature;
 
-			AST_RWLIST_RDLOCK(&feature_list);
-			if (!(feature = find_dynamic_feature(var->name)) &&
-			    !(feature = ast_find_call_feature(var->name))) {
-				AST_RWLIST_UNLOCK(&feature_list);
+			ast_rdlock_call_features();
+			feature = ast_find_call_feature(var->name);
+			ast_unlock_call_features();
+			if (!feature) {
 				ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
 				continue;
 			}
-			AST_RWLIST_UNLOCK(&feature_list);
 
 			register_group_feature(fg, var->value, feature);
 		}
@@ -6855,41 +6853,41 @@
 
 	ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
 
-	ast_rwlock_rdlock(&features_lock);
+	ast_rdlock_call_features();
 	for (i = 0; i < FEATURES_COUNT; i++)
 		ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
-	ast_rwlock_unlock(&features_lock);
+	ast_unlock_call_features();
 
 	ast_cli(a->fd, "\n");
 	ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
 	ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
-	if (AST_RWLIST_EMPTY(&feature_list)) {
+	ast_rdlock_call_features();
+	if (AST_LIST_EMPTY(&feature_list)) {
 		ast_cli(a->fd, "(none)\n");
 	} else {
-		AST_RWLIST_RDLOCK(&feature_list);
-		AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
+		AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
 			ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
 		}
-		AST_RWLIST_UNLOCK(&feature_list);
-	}
+	}
+	ast_unlock_call_features();
 
 	ast_cli(a->fd, "\nFeature Groups:\n");
 	ast_cli(a->fd, "---------------\n");
+	AST_RWLIST_RDLOCK(&feature_groups);
 	if (AST_RWLIST_EMPTY(&feature_groups)) {
 		ast_cli(a->fd, "(none)\n");
 	} else {
 		struct feature_group *fg;
 		struct feature_group_exten *fge;
 
-		AST_RWLIST_RDLOCK(&feature_groups);
 		AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
 			ast_cli(a->fd, "===> Group: %s\n", fg->gname);
 			AST_LIST_TRAVERSE(&fg->features, fge, entry) {
 				ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
 			}
 		}
-		AST_RWLIST_UNLOCK(&feature_groups);
-	}
+	}
+	AST_RWLIST_UNLOCK(&feature_groups);
 
 	iter = ao2_iterator_init(parkinglots, 0);
 	while ((curlot = ao2_iterator_next(&iter))) {
@@ -7260,7 +7258,7 @@
 	return RESULT_SUCCESS;
 }
 
-/*! 
+/*!
  * \brief Dump parking lot status
  * \param s
  * \param m
@@ -8647,8 +8645,12 @@
 {
 	struct feature_datastore *feature_ds;
 	struct feature_exten *fe;
-
-	if (!ast_find_call_feature(data)) {
+	struct ast_call_feature *feat;
+
+	ast_rdlock_call_features();
+	feat = ast_find_call_feature(data);
+	ast_unlock_call_features();
+	if (!feat) {
 		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
 		return -1;
 	}

Modified: team/kmoore/stasis-bridging-channel_events/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-bridging-channel_events/main/manager.c?view=diff&rev=385337&r1=385336&r2=385337
==============================================================================
--- team/kmoore/stasis-bridging-channel_events/main/manager.c (original)
+++ team/kmoore/stasis-bridging-channel_events/main/manager.c Thu Apr 11 12:35:22 2013
@@ -3892,7 +3892,10 @@
 		return 0;
 	}
 
-	if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
+	ast_rdlock_call_features();
+	atxfer_feature = ast_find_call_feature("atxfer");
+	ast_unlock_call_features();
+	if (!atxfer_feature) {
 		astman_send_error(s, m, "No attended transfer feature found");
 		return 0;
 	}




More information about the asterisk-commits mailing list