[asterisk-commits] rmudgett: trunk r395340 - in /trunk: include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 24 18:40:13 CDT 2013


Author: rmudgett
Date: Wed Jul 24 18:40:12 2013
New Revision: 395340

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395340
Log:
Simplify interval hooks since there is only one bridge threading model now.

* Convert interval timers to use the ast_waitfor_nandfds() timeout.

* Remove bridge channel action for intervals.  Now the main loop handles
running interval hooks.

Modified:
    trunk/include/asterisk/bridging_channel_internal.h
    trunk/include/asterisk/bridging_features.h
    trunk/main/bridging.c
    trunk/main/bridging_channel.c

Modified: trunk/include/asterisk/bridging_channel_internal.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_channel_internal.h?view=diff&rev=395340&r1=395339&r2=395340
==============================================================================
--- trunk/include/asterisk/bridging_channel_internal.h (original)
+++ trunk/include/asterisk/bridging_channel_internal.h Wed Jul 24 18:40:12 2013
@@ -40,8 +40,6 @@
 enum bridge_channel_action_type {
 	/*! Bridged channel is to detect a feature hook */
 	BRIDGE_CHANNEL_ACTION_FEATURE,
-	/*! Bridged channel is to act on an interval hook */
-	BRIDGE_CHANNEL_ACTION_INTERVAL,
 	/*! Bridged channel is to send a DTMF stream out */
 	BRIDGE_CHANNEL_ACTION_DTMF_STREAM,
 	/*! Bridged channel is to indicate talking start */

Modified: trunk/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_features.h?view=diff&rev=395340&r1=395339&r2=395340
==============================================================================
--- trunk/include/asterisk/bridging_features.h (original)
+++ trunk/include/asterisk/bridging_features.h Wed Jul 24 18:40:12 2013
@@ -226,8 +226,6 @@
 	struct ast_bridge_hook_timer_parms timer;
 };
 
-#define BRIDGE_FEATURES_INTERVAL_RATE 10
-
 /*!
  * \brief Structure that contains features information
  */
@@ -238,8 +236,6 @@
 	struct ao2_container *other_hooks;
 	/*! Attached interval hooks */
 	struct ast_heap *interval_hooks;
-	/*! Used to determine when interval based features should be checked */
-	struct ast_timer *interval_timer;
 	/*! Limits feature data */
 	struct ast_bridge_features_limits *limits;
 	/*! Feature flags that are enabled */

Modified: trunk/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging.c?view=diff&rev=395340&r1=395339&r2=395340
==============================================================================
--- trunk/main/bridging.c (original)
+++ trunk/main/bridging.c Wed Jul 24 18:40:12 2013
@@ -3641,14 +3641,6 @@
 		return -1;
 	}
 
-	if (!features->interval_timer) {
-		if (!(features->interval_timer = ast_timer_open())) {
-			ast_log(LOG_ERROR, "Failed to open a timer when adding a timed bridging feature.\n");
-			return -1;
-		}
-		ast_timer_set_rate(features->interval_timer, BRIDGE_FEATURES_INTERVAL_RATE);
-	}
-
 	/* Allocate new hook and setup it's various variables */
 	hook = (struct ast_bridge_hook_timer *) bridge_hook_generic(sizeof(*hook), callback,
 		hook_pvt, destructor, remove_flags);
@@ -3920,11 +3912,6 @@
 			ao2_ref(hook, -1);
 		}
 		features->interval_hooks = ast_heap_destroy(features->interval_hooks);
-	}
-
-	if (features->interval_timer) {
-		ast_timer_close(features->interval_timer);
-		features->interval_timer = NULL;
 	}
 
 	/* If the features contains a limits pvt, destroy that as well. */

Modified: trunk/main/bridging_channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridging_channel.c?view=diff&rev=395340&r1=395339&r2=395340
==============================================================================
--- trunk/main/bridging_channel.c (original)
+++ trunk/main/bridging_channel.c Wed Jul 24 18:40:12 2013
@@ -698,20 +698,6 @@
 		bridge_channel, parkee_uuid, parker_uuid, app_data);
 }
 
-static int bridge_channel_interval_ready(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook_timer *hook;
-	int ready;
-
-	ast_heap_wrlock(features->interval_hooks);
-	hook = ast_heap_peek(features->interval_hooks, 1);
-	ready = hook && ast_tvdiff_ms(hook->timer.trip_time, ast_tvnow()) <= 0;
-	ast_heap_unlock(features->interval_hooks);
-
-	return ready;
-}
-
 int ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
 {
 	struct ast_frame action = {
@@ -833,15 +819,26 @@
 	ast_bridge_unlock(bridge_channel->bridge);
 }
 
-/*! \brief Internal function that activates interval hooks on a bridge channel */
-static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel)
-{
+/*!
+ * \internal
+ * \brief Handle bridge channel interval expiration.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to run expired intervals on.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_heap *interval_hooks;
 	struct ast_bridge_hook_timer *hook;
 	struct timeval start;
-
-	ast_heap_wrlock(bridge_channel->features->interval_hooks);
+	int hook_run = 0;
+
+	interval_hooks = bridge_channel->features->interval_hooks;
+	ast_heap_wrlock(interval_hooks);
 	start = ast_tvnow();
-	while ((hook = ast_heap_peek(bridge_channel->features->interval_hooks, 1))) {
+	while ((hook = ast_heap_peek(interval_hooks, 1))) {
 		int interval;
 		unsigned int execution_time;
 
@@ -851,17 +848,22 @@
 			break;
 		}
 		ao2_ref(hook, +1);
-		ast_heap_unlock(bridge_channel->features->interval_hooks);
+		ast_heap_unlock(interval_hooks);
+
+		if (!hook_run) {
+			hook_run = 1;
+			bridge_channel_suspend(bridge_channel);
+			ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+		}
 
 		ast_debug(1, "Executing hook %p on %p(%s)\n",
 			hook, bridge_channel, ast_channel_name(bridge_channel->chan));
 		interval = hook->generic.callback(bridge_channel->bridge, bridge_channel,
 			hook->generic.hook_pvt);
 
-		ast_heap_wrlock(bridge_channel->features->interval_hooks);
-		if (ast_heap_peek(bridge_channel->features->interval_hooks,
-			hook->timer.heap_index) != hook
-			|| !ast_heap_remove(bridge_channel->features->interval_hooks, hook)) {
+		ast_heap_wrlock(interval_hooks);
+		if (ast_heap_peek(interval_hooks, hook->timer.heap_index) != hook
+			|| !ast_heap_remove(interval_hooks, hook)) {
 			/* Interval hook is already removed from the bridge_channel. */
 			ao2_ref(hook, -1);
 			continue;
@@ -898,12 +900,17 @@
 		hook->timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->timer.interval - execution_time, 1000));
 		hook->timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1);
 
-		if (ast_heap_push(bridge_channel->features->interval_hooks, hook)) {
+		if (ast_heap_push(interval_hooks, hook)) {
 			/* Could not push the hook back onto the heap. */
 			ao2_ref(hook, -1);
 		}
 	}
-	ast_heap_unlock(bridge_channel->features->interval_hooks);
+	ast_heap_unlock(interval_hooks);
+
+	if (hook_run) {
+		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+		bridge_channel_unsuspend(bridge_channel);
+	}
 }
 
 static int bridge_channel_write_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
@@ -1138,13 +1145,6 @@
 static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
 {
 	switch (action->subclass.integer) {
-	case BRIDGE_CHANNEL_ACTION_INTERVAL:
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_interval(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-		break;
 	case BRIDGE_CHANNEL_ACTION_FEATURE:
 		bridge_channel_suspend(bridge_channel);
 		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
@@ -1380,6 +1380,9 @@
 	/* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */
 	pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", NULL);
 	pbx_builtin_setvar_helper(bridge_channel->chan, "ATTENDEDTRANSFER", NULL);
+
+	/* Wake up the bridge channel thread to reevaluate any interval timers. */
+	ast_queue_frame(bridge_channel->chan, &ast_null_frame);
 
 	bridge->reconfigured = 1;
 	return 0;
@@ -1521,36 +1524,6 @@
 	ast_frfree(fr);
 }
 
-/*!
- * \internal
- * \brief Handle bridge channel interval expiration.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to check interval on.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_timer *interval_timer;
-
-	interval_timer = bridge_channel->features->interval_timer;
-	if (interval_timer) {
-		if (ast_wait_for_input(ast_timer_fd(interval_timer), 0) == 1) {
-			ast_timer_ack(interval_timer, 1);
-			if (bridge_channel_interval_ready(bridge_channel)) {
-/* BUGBUG since this is now only run by the channel thread, there is no need to queue the action once this intervals become a first class wait item in bridge_channel_wait(). */
-				struct ast_frame interval_action = {
-					.frametype = AST_FRAME_BRIDGE_ACTION,
-					.subclass.integer = BRIDGE_CHANNEL_ACTION_INTERVAL,
-				};
-
-				ast_bridge_channel_queue_frame(bridge_channel, &interval_action);
-			}
-		}
-	}
-}
-
 /*! \brief Internal function to handle DTMF from a channel */
 static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
@@ -1638,6 +1611,39 @@
 
 /*!
  * \internal
+ * \brief Determine how long till the next timer interval.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to determine how long can wait.
+ *
+ * \retval ms Number of milliseconds to wait.
+ * \retval -1 to wait forever.
+ */
+static int bridge_channel_next_interval(struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_heap *interval_hooks = bridge_channel->features->interval_hooks;
+	struct ast_bridge_hook_timer *hook;
+	int ms;
+
+	ast_heap_wrlock(interval_hooks);
+	hook = ast_heap_peek(interval_hooks, 1);
+	if (hook) {
+		ms = ast_tvdiff_ms(hook->timer.trip_time, ast_tvnow());
+		if (ms < 0) {
+			/* Expire immediately.  An interval hook is ready to run. */
+			ms = 0;
+		}
+	} else {
+		/* No hook so wait forever. */
+		ms = -1;
+	}
+	ast_heap_unlock(interval_hooks);
+
+	return ms;
+}
+
+/*!
+ * \internal
  * \brief Wait for something to happen on the bridge channel and handle it.
  * \since 12.0.0
  *
@@ -1649,7 +1655,7 @@
  */
 static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel)
 {
-	int ms = -1;
+	int ms;
 	int outfd;
 	struct ast_channel *chan;
 
@@ -1669,7 +1675,7 @@
 		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. */
+		ms = bridge_channel_next_interval(bridge_channel);
 		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1,
 			&bridge_channel->alert_pipe[0], 1, NULL, &outfd, &ms);
 		bridge_channel->waiting = 0;
@@ -1686,10 +1692,12 @@
 		if (!bridge_channel->suspended
 			&& bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
 			if (chan) {
-				bridge_channel_handle_interval(bridge_channel);
 				bridge_handle_trip(bridge_channel);
 			} else if (-1 < outfd) {
 				bridge_channel_handle_write(bridge_channel);
+			} else if (ms == 0) {
+				/* An interval expired. */
+				bridge_channel_handle_interval(bridge_channel);
 			}
 		}
 		bridge_channel->activity = AST_BRIDGE_CHANNEL_THREAD_IDLE;




More information about the asterisk-commits mailing list