[asterisk-commits] kpfleming: branch 1.6.1 r184765 - in /branches/1.6.1: ./ channels/ include/as...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Mar 27 14:17:28 CDT 2009


Author: kpfleming
Date: Fri Mar 27 14:17:22 2009
New Revision: 184765

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=184765
Log:
Merged revisions 184762 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

........
  r184762 | kpfleming | 2009-03-27 14:10:32 -0500 (Fri, 27 Mar 2009) | 12 lines
  
  Improve timing interface to remember which provider provided a timer
  
  The ability to load/unload timing interfaces is nice, but it means that when a timer is allocated, it may come from provider A, but later provider B becomes the 'preferred' provider. If this happens, all timer API calls on the timer that was provided by provider A will actually be handed to provider B, which will say WTF and return an error.
  
  This patch changes the timer API to include a pointer to the provider of the timer handle so that future operations on the timer will be forwarded to the proper provider.
  
  (closes issue #14697)
  Reported by: moy
  
  Review: http://reviewboard.digium.com/r/211/
........

Modified:
    branches/1.6.1/   (props changed)
    branches/1.6.1/channels/chan_iax2.c
    branches/1.6.1/include/asterisk/channel.h
    branches/1.6.1/include/asterisk/timing.h
    branches/1.6.1/main/channel.c
    branches/1.6.1/main/timing.c

Propchange: branches/1.6.1/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.1/channels/chan_iax2.c
URL: http://svn.digium.com/svn-view/asterisk/branches/1.6.1/channels/chan_iax2.c?view=diff&rev=184765&r1=184764&r2=184765
==============================================================================
--- branches/1.6.1/channels/chan_iax2.c (original)
+++ branches/1.6.1/channels/chan_iax2.c Fri Mar 27 14:17:22 2009
@@ -175,7 +175,7 @@
 
 static int srvlookup = 0;
 
-static int timingfd = -1;				/* Timing file descriptor */
+static struct ast_timer *timer;				/* Timer for trunking */
 
 static struct ast_netsock_list *netsock;
 static struct ast_netsock_list *outsock;		/*!< used if sourceaddress specified and bindaddr == INADDR_ANY */
@@ -7550,8 +7550,8 @@
 	if (iaxtrunkdebug)
 		ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
 
-	if (timingfd > -1) { 
-		ast_timer_ack(timingfd, 1);
+	if (timer) { 
+		ast_timer_ack(timer, 1);
 	}
 
 	/* For each peer that supports trunking... */
@@ -10359,8 +10359,8 @@
 	int res, count, wakeup;
 	struct iax_frame *f;
 
-	if (timingfd > -1)
-		ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL);
+	if (timer)
+		ast_io_add(io, ast_timer_fd(timer), timing_read, AST_IO_IN | AST_IO_PRI, NULL);
 	
 	for(;;) {
 		pthread_testcancel();
@@ -10669,7 +10669,7 @@
 				ast_string_field_set(peer, dbsecret, v->value);
 			} else if (!strcasecmp(v->name, "trunk")) {
 				ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK);	
-				if (ast_test_flag(peer, IAX_TRUNK) && (timingfd < 0)) {
+				if (ast_test_flag(peer, IAX_TRUNK) && !timer) {
 					ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without a timing interface\n", peer->name);
 					ast_clear_flag(peer, IAX_TRUNK);
 				}
@@ -10924,7 +10924,7 @@
 				ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
 			} else if (!strcasecmp(v->name, "trunk")) {
 				ast_set2_flag(user, ast_true(v->value), IAX_TRUNK);	
-				if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) {
+				if (ast_test_flag(user, IAX_TRUNK) && !timer) {
 					ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name);
 					ast_clear_flag(user, IAX_TRUNK);
 				}
@@ -12321,8 +12321,8 @@
 	ao2_ref(users, -1);
 	ao2_ref(iax_peercallno_pvts, -1);
 	ao2_ref(iax_transfercallno_pvts, -1);
-	if (timingfd > -1) {
-		ast_timer_close(timingfd);
+	if (timer) {
+		ast_timer_close(timer);
 	}
 
 	con = ast_context_find(regcontext);
@@ -12463,9 +12463,8 @@
 	ast_manager_register( "IAXpeerlist", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peer_list, "List IAX Peers" );
 	ast_manager_register( "IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats, "Show IAX Netstats" );
 
-	timingfd = ast_timer_open();
-	if (timingfd > -1) {
-		ast_timer_set_rate(timingfd, trunkfreq);
+	if ((timer = ast_timer_open())) {
+		ast_timer_set_rate(timer, trunkfreq);
 	}
 
 	if (set_config(config, 0) == -1) {

Modified: branches/1.6.1/include/asterisk/channel.h
URL: http://svn.digium.com/svn-view/asterisk/branches/1.6.1/include/asterisk/channel.h?view=diff&rev=184765&r1=184764&r2=184765
==============================================================================
--- branches/1.6.1/include/asterisk/channel.h (original)
+++ branches/1.6.1/include/asterisk/channel.h Fri Mar 27 14:17:22 2009
@@ -492,7 +492,13 @@
 
 	unsigned short transfercapability;		/*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
 
-	char unused_old_dtmfq[AST_MAX_EXTENSION];			/*!< (deprecated, use readq instead) Any/all queued DTMF characters */
+	union {
+		char unused_old_dtmfq[AST_MAX_EXTENSION];			/*!< (deprecated, use readq instead) Any/all queued DTMF characters */
+		struct {
+			struct ast_timer *timer;				/*!< timer object that provided timingfd */
+		};
+	};
+
 	char context[AST_MAX_CONTEXT];			/*!< Dialplan: Current extension context */
 	char exten[AST_MAX_EXTENSION];			/*!< Dialplan: Current extension number */
 	char macrocontext[AST_MAX_CONTEXT];		/*!< Macro: Current non-macro context. See app_macro.c */

Modified: branches/1.6.1/include/asterisk/timing.h
URL: http://svn.digium.com/svn-view/asterisk/branches/1.6.1/include/asterisk/timing.h?view=diff&rev=184765&r1=184764&r2=184765
==============================================================================
--- branches/1.6.1/include/asterisk/timing.h (original)
+++ branches/1.6.1/include/asterisk/timing.h Fri Mar 27 14:17:22 2009
@@ -93,7 +93,7 @@
  */
 #define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self)
 void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
-		struct ast_module *mod);
+				     struct ast_module *mod);
 
 /*!
  * \brief Unregister a previously registered timing interface.
@@ -107,45 +107,57 @@
  */
 int ast_unregister_timing_interface(void *handle);
 
-/*!
- * \brief Open a timing fd
+struct ast_timer;
+
+/*!
+ * \brief Open a timer
+ *
+ * \retval NULL on error, with errno set
+ * \retval non-NULL timer handle on success
+ * \since 1.6.1
+ */
+struct ast_timer *ast_timer_open(void);
+
+/*!
+ * \brief Close an opened timing handle
+ *
+ * \param handle timer handle returned from timer_open()
+ *
+ * \return nothing
+ * \since 1.6.1
+ */
+void ast_timer_close(struct ast_timer *handle);
+
+/*!
+ * \brief Get a poll()-able file descriptor for a timer
+ *
+ * \param handle timer handle returned from timer_open()
+ *
+ * \return file descriptor which can be used with poll() to wait for events
+ * \since 1.6.1
+ */
+int ast_timer_fd(const struct ast_timer *handle);
+
+/*!
+ * \brief Set the timing tick rate
+ *
+ * \param handle timer handle returned from timer_open()
+ * \param rate ticks per second, 0 turns the ticks off if needed
+ *
+ * Use this function if you want the timer to show input at a certain
+ * rate.  The other alternative use of a timer is the continuous
+ * mode.
  *
  * \retval -1 error, with errno set
- * \retval >=0 success
- * \since 1.6.1
- */
-int ast_timer_open(void);
-
-/*!
- * \brief Close an opened timing handle
- *
- * \param handle timing fd returned from timer_open()
- *
- * \return nothing
- * \since 1.6.1
- */
-void ast_timer_close(int handle);
-
-/*!
- * \brief Set the timing tick rate
- *
- * \param handle timing fd returned from timer_open()
- * \param rate ticks per second, 0 turns the ticks off if needed
- *
- * Use this function if you want the timing fd to show input at a certain
- * rate.  The other alternative use of a timing fd, is using the continuous
- * mode.
- *
- * \retval -1 error, with errno set
- * \retval 0 success
- * \since 1.6.1
- */
-int ast_timer_set_rate(int handle, unsigned int rate);
+ * \retval 0 success
+ * \since 1.6.1
+ */
+int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate);
 
 /*!
  * \brief Acknowledge a timer event
  *
- * \param handle timing fd returned from timer_open()
+ * \param handle timer handle returned from timer_open()
  * \param quantity number of timer events to acknowledge
  *
  * \note This function should only be called if timer_get_event()
@@ -154,55 +166,55 @@
  * \return nothing
  * \since 1.6.1
  */
-void ast_timer_ack(int handle, unsigned int quantity);
+void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity);
 
 /*!
  * \brief Enable continuous mode
  *
- * \param handle timing fd returned from timer_open()
- *
- * Continuous mode causes poll() on the timing fd to immediately return
+ * \param handle timer handle returned from timer_open()
+ *
+ * Continuous mode causes poll() on the timer's fd to immediately return
  * always until continuous mode is disabled.
  *
  * \retval -1 failure, with errno set
  * \retval 0 success
  * \since 1.6.1
  */
-int ast_timer_enable_continuous(int handle);
+int ast_timer_enable_continuous(const struct ast_timer *handle);
 
 /*!
  * \brief Disable continuous mode
  *
- * \param handle timing fd returned from timer_close()
+ * \param handle timer handle returned from timer_close()
  *
  * \retval -1 failure, with errno set
  * \retval 0 success
  * \since 1.6.1
  */
-int ast_timer_disable_continuous(int handle);
-
-/*!
- * \brief Determine timing event
- *
- * \param handle timing fd returned by timer_open()
- *
- * After poll() indicates that there is input on the timing fd, this will
+int ast_timer_disable_continuous(const struct ast_timer *handle);
+
+/*!
+ * \brief Retrieve timing event
+ *
+ * \param handle timer handle returned by timer_open()
+ *
+ * After poll() indicates that there is input on the timer's fd, this will
  * be called to find out what triggered it.
  *
- * \return which event triggered the timing fd
- * \since 1.6.1
- */
-enum ast_timer_event ast_timer_get_event(int handle);
-
-/*!
- * \brief Get maximum rate supported for a timing handle
- *
- * \param handle timing fd returned by timer_open()
- *
- * \return maximum rate supported for timing handle
- * \since 1.6.1
- */
-unsigned int ast_timer_get_max_rate(int handle);
+ * \return which event triggered the timer
+ * \since 1.6.1
+ */
+enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle);
+
+/*!
+ * \brief Get maximum rate supported for a timer
+ *
+ * \param handle timer handle returned by timer_open()
+ *
+ * \return maximum rate supported by timer
+ * \since 1.6.1
+ */
+unsigned int ast_timer_get_max_rate(const struct ast_timer *handle);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

Modified: branches/1.6.1/main/channel.c
URL: http://svn.digium.com/svn-view/asterisk/branches/1.6.1/main/channel.c?view=diff&rev=184765&r1=184764&r2=184765
==============================================================================
--- branches/1.6.1/main/channel.c (original)
+++ branches/1.6.1/main/channel.c Fri Mar 27 14:17:22 2009
@@ -806,17 +806,19 @@
 #endif
 	}
 
-	tmp->timingfd = ast_timer_open();
-	if (tmp->timingfd > -1) {
+	if ((tmp->timer = ast_timer_open())) {
 		needqueue = 0;
+		tmp->timingfd = ast_timer_fd(tmp->timer);
+	} else {
+		tmp->timingfd = -1;
 	}
 
 	if (needqueue) {
 		if (pipe(tmp->alertpipe)) {
 			ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
 alertpipe_failed:
-			if (tmp->timingfd > -1) {
-				ast_timer_close(tmp->timingfd);
+			if (tmp->timer) {
+				ast_timer_close(tmp->timer);
 			}
 
 			sched_context_destroy(tmp->sched);
@@ -1005,7 +1007,7 @@
 				chan->name, f->frametype, f->subclass, qlen, strerror(errno));
 		}
 	} else if (chan->timingfd > -1) {
-		ast_timer_enable_continuous(chan->timingfd);
+		ast_timer_enable_continuous(chan->timer);
 	} else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) {
 		pthread_kill(chan->blocker, SIGURG);
 	}
@@ -1355,8 +1357,9 @@
 		close(fd);
 	if ((fd = chan->alertpipe[1]) > -1)
 		close(fd);
-	if ((fd = chan->timingfd) > -1)
-		ast_timer_close(fd);
+	if (chan->timer) {
+		ast_timer_close(chan->timer);
+	}
 #ifdef HAVE_EPOLL
 	for (i = 0; i < AST_MAX_FDS; i++) {
 		if (chan->epfd_data[i])
@@ -2298,13 +2301,13 @@
 		data = NULL;
 	}
 
-	if (rate && rate > (max_rate = ast_timer_get_max_rate(c->timingfd))) {
+	if (rate && rate > (max_rate = ast_timer_get_max_rate(c->timer))) {
 		real_rate = max_rate;
 	}
 
 	ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate);
 
-	res = ast_timer_set_rate(c->timingfd, real_rate);
+	res = ast_timer_set_rate(c->timer, real_rate);
 
 	c->timingfunc = func;
 	c->timingdata = data;
@@ -2557,11 +2560,11 @@
 
 		ast_clear_flag(chan, AST_FLAG_EXCEPTION);
 
-		res = ast_timer_get_event(chan->timingfd);
+		res = ast_timer_get_event(chan->timer);
 
 		switch (res) {
 		case AST_TIMING_EVENT_EXPIRED:
-			ast_timer_ack(chan->timingfd, 1);
+			ast_timer_ack(chan->timer, 1);
 
 			if (chan->timingfunc) {
 				/* save a copy of func/data before unlocking the channel */
@@ -2571,7 +2574,7 @@
 				ast_channel_unlock(chan);
 				func(data);
 			} else {
-				ast_timer_set_rate(chan->timingfd, 0);
+				ast_timer_set_rate(chan->timer, 0);
 				chan->fdno = -1;
 				ast_channel_unlock(chan);
 			}
@@ -2582,7 +2585,7 @@
 		case AST_TIMING_EVENT_CONTINUOUS:
 			if (AST_LIST_EMPTY(&chan->readq) || 
 				!AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) {
-				ast_timer_disable_continuous(chan->timingfd);
+				ast_timer_disable_continuous(chan->timer);
 			}
 			break;
 		}

Modified: branches/1.6.1/main/timing.c
URL: http://svn.digium.com/svn-view/asterisk/branches/1.6.1/main/timing.c?view=diff&rev=184765&r1=184764&r2=184765
==============================================================================
--- branches/1.6.1/main/timing.c (original)
+++ branches/1.6.1/main/timing.c Fri Mar 27 14:17:22 2009
@@ -49,6 +49,11 @@
 
 static struct ast_heap *timing_interfaces;
 
+struct ast_timer {
+	int fd;
+	struct timing_holder *holder;
+};
+
 static int timing_holder_cmp(void *_h1, void *_h2)
 {
 	struct timing_holder *h1 = _h1;
@@ -64,16 +69,16 @@
 }
 
 void *_ast_register_timing_interface(struct ast_timing_interface *funcs, 
-		struct ast_module *mod)
+				     struct ast_module *mod)
 {
 	struct timing_holder *h;
 
 	if (!funcs->timer_open ||
 	    !funcs->timer_close ||
-		!funcs->timer_set_rate ||
+	    !funcs->timer_set_rate ||
 	    !funcs->timer_ack ||
 	    !funcs->timer_get_event ||
-		!funcs->timer_get_max_rate ||
+	    !funcs->timer_get_max_rate ||
 	    !funcs->timer_enable_continuous ||
 	    !funcs->timer_disable_continuous) {
 		return NULL;
@@ -111,10 +116,11 @@
 	return res;
 }
 
-int ast_timer_open(void)
+struct ast_timer *ast_timer_open(void)
 {
 	int fd = -1;
 	struct timing_holder *h;
+	struct ast_timer *t = NULL;
 
 	ast_heap_rdlock(timing_interfaces);
 
@@ -123,124 +129,88 @@
 		ast_module_ref(h->mod);
 	}
 
+	if (fd != -1) {
+		if (!(t = ast_calloc(1, sizeof(*t)))) {
+			h->iface->timer_close(fd);
+		} else {
+			t->fd = fd;
+			t->holder = h;
+		}
+	}
+
 	ast_heap_unlock(timing_interfaces);
 
-	return fd;
-}
-
-void ast_timer_close(int timer)
-{
-	struct timing_holder *h;
-
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		h->iface->timer_close(timer);
-		ast_module_unref(h->mod);
-	}
-
-	ast_heap_unlock(timing_interfaces);
-}
-
-int ast_timer_set_rate(int handle, unsigned int rate)
-{
-	struct timing_holder *h;
-	int res = -1;
-
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		res = h->iface->timer_set_rate(handle, rate);
-	}
-
-	ast_heap_unlock(timing_interfaces);
-
-	return res;
-}
-
-void ast_timer_ack(int handle, unsigned int quantity)
-{
-	struct timing_holder *h;
-
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		h->iface->timer_ack(handle, quantity);
-	}
-
-	ast_heap_unlock(timing_interfaces);
-}
-
-int ast_timer_enable_continuous(int handle)
-{
-	struct timing_holder *h;
-	int res = -1;
-
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		res = h->iface->timer_enable_continuous(handle);
-	}
-
-	ast_heap_unlock(timing_interfaces);
-
-	return res;
-}
-
-int ast_timer_disable_continuous(int handle)
-{
-	struct timing_holder *h;
-	int res = -1;
-
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		res = h->iface->timer_disable_continuous(handle);
-	}
-
-	ast_heap_unlock(timing_interfaces);
-
-	return res;
-}
-
-enum ast_timer_event ast_timer_get_event(int handle)
-{
-	struct timing_holder *h;
+	return t;
+}
+
+void ast_timer_close(struct ast_timer *handle)
+{
+	handle->holder->iface->timer_close(handle->fd);
+	ast_module_unref(handle->holder->mod);
+	ast_free(handle);
+}
+
+int ast_timer_fd(const struct ast_timer *handle)
+{
+	return handle->fd;
+}
+
+int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
+{
+	int res = -1;
+
+	res = handle->holder->iface->timer_set_rate(handle->fd, rate);
+
+	return res;
+}
+
+void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
+{
+	handle->holder->iface->timer_ack(handle->fd, quantity);
+}
+
+int ast_timer_enable_continuous(const struct ast_timer *handle)
+{
+	int res = -1;
+
+	res = handle->holder->iface->timer_enable_continuous(handle->fd);
+
+	return res;
+}
+
+int ast_timer_disable_continuous(const struct ast_timer *handle)
+{
+	int res = -1;
+
+	res = handle->holder->iface->timer_disable_continuous(handle->fd);
+
+	return res;
+}
+
+enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
+{
 	enum ast_timer_event res = -1;
 
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		res = h->iface->timer_get_event(handle);
-	}
-
-	ast_heap_unlock(timing_interfaces);
-
-	return res;
-}
-
-unsigned int ast_timer_get_max_rate(int handle)
-{
-	struct timing_holder *h;
+	res = handle->holder->iface->timer_get_event(handle->fd);
+
+	return res;
+}
+
+unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
+{
 	unsigned int res = 0;
 
-	ast_heap_rdlock(timing_interfaces);
-
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		res = h->iface->timer_get_max_rate(handle);
-	}
-
-	ast_heap_unlock(timing_interfaces);
+	res = handle->holder->iface->timer_get_max_rate(handle->fd);
 
 	return res;
 }
 
 static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	int fd, count = 0;
+	struct ast_timer *timer;
+	int count = 0;
 	struct timeval start, end;
 	unsigned int test_rate = 50;
-	struct timing_holder *h;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -268,26 +238,21 @@
 
 	ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
 
-	if ((fd = ast_timer_open()) == -1) {
+	if (!(timer = ast_timer_open())) {
 		ast_cli(a->fd, "Failed to open timing fd\n");
 		return CLI_FAILURE;
 	}
 
-	ast_heap_rdlock(timing_interfaces);
-	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		ast_cli(a->fd, "Using the '%s' timing module for this test.\n", h->iface->name);
-		h = NULL;
-	}
-	ast_heap_unlock(timing_interfaces);
+	ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
 
 	start = ast_tvnow();
 
-	ast_timer_set_rate(fd, test_rate);
+	ast_timer_set_rate(timer, test_rate);
 
 	while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
 		int res;
 		struct pollfd pfd = {
-			.fd = fd,
+			.fd = ast_timer_fd(timer),
 			.events = POLLIN | POLLPRI,
 		};
 
@@ -295,7 +260,7 @@
 
 		if (res == 1) {
 			count++;
-			ast_timer_ack(fd, 1);
+			ast_timer_ack(timer, 1);
 		} else if (!res) {
 			ast_cli(a->fd, "poll() timed out!  This is bad.\n");
 		} else if (errno != EAGAIN && errno != EINTR) {
@@ -303,7 +268,7 @@
 		}
 	}
 
-	ast_timer_close(fd);
+	ast_timer_close(timer);
 
 	ast_cli(a->fd, "It has been %d milliseconds, and we got %d timer ticks\n", 
 		ast_tvdiff_ms(end, start), count);




More information about the asterisk-commits mailing list