[Asterisk-Dev] High resolution timers using POSIX clocks instead of zaptel

David Woodhouse dwmw2 at infradead.org
Fri May 27 03:33:12 MST 2005


Using zaptel just for a time source is silly. We should use POSIX timers
instead. Here's a start, but I don't know how long it'll be before I can
get to finish it, so I thought I'd post it here in the hope that someone
else will pick it up.

This demonstrates how to set up POSIX timers to interrupt periodically
by giving you a signal. Having got that far, I'm not entirely sure how
best to _use_ it within Asterisk, since pselect() doesn't work properly.
I'm not even sure that the thread which sets up the channel will always
be the thread which should receive the signal. Perhaps we should use a
thread which is dedicated to setting up timers and handling signals, and
which wakes others by using a pipe like the existing timingfd -- but
that increases the latency.

Index: Makefile
===================================================================
RCS file: /usr/cvsroot/asterisk/Makefile,v
retrieving revision 1.160
diff -u -r1.160 Makefile
--- Makefile	20 May 2005 03:18:35 -0000	1.160
+++ Makefile	27 May 2005 10:25:56 -0000
@@ -240,7 +240,7 @@
 endif
 LIBS+=-lncurses -lm
 ifeq (${OSARCH},Linux)
-LIBS+=-lresolv  #-lnjamd
+LIBS+=-lresolv -lrt  #-lnjamd
 endif
 ifeq (${OSARCH},Darwin)
 LIBS+=-lresolv
@@ -266,7 +266,7 @@
 	cdr.o tdd.o acl.o rtp.o manager.o asterisk.o \
 	dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
 	astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
-	utils.o config_old.o plc.o jitterbuf.o dnsmgr.o
+	utils.o config_old.o plc.o jitterbuf.o dnsmgr.o timer.o
 ifeq (${OSARCH},Darwin)
 OBJS+=poll.o dlfcn.o
 ASTLINK=-Wl,-dynamic
Index: channel.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channel.c,v
retrieving revision 1.195
diff -u -r1.195 channel.c
--- channel.c	15 May 2005 04:48:30 -0000	1.195
+++ channel.c	27 May 2005 10:25:56 -0000
@@ -53,6 +53,7 @@
 #include "asterisk/lock.h"
 #include "asterisk/app.h"
 #include "asterisk/transcap.h"
+#include "asterisk/timer.h"
 #include "asterisk.h"
 
 /* uncomment if you have problems with 'monitoring' synchronized files */
@@ -359,18 +360,8 @@
 	for (x=0; x<AST_MAX_FDS - 1; x++)
 		tmp->fds[x] = -1;
 
-#ifdef ZAPTEL_OPTIMIZATIONS
-	tmp->timingfd = open("/dev/zap/timer", O_RDWR);
-	if (tmp->timingfd > -1) {
-		/* Check if timing interface supports new
-		   ping/pong scheme */
-		flags = 1;
-		if (!ioctl(tmp->timingfd, ZT_TIMERPONG, &flags))
-			needqueue = 0;
-	}
-#else
-	tmp->timingfd = -1;					
-#endif					
+	if (ast_init_channel_timer(tmp))
+		needqueue = 0;
 
 	if (needqueue) {
 		if (pipe(tmp->alertpipe)) {
@@ -3377,6 +3372,7 @@
 void ast_channels_init(void)
 {
 	ast_cli_register(&cli_show_channeltypes);
+	ast_check_posix_timers();
 }
 
 /*--- ast_print_group: Print call group and pickup group ---*/
Index: include/asterisk/channel.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/channel.h,v
retrieving revision 1.84
diff -u -r1.84 channel.h
--- include/asterisk/channel.h	15 May 2005 04:48:30 -0000	1.84
+++ include/asterisk/channel.h	27 May 2005 10:25:59 -0000
@@ -22,6 +22,7 @@
 #include "asterisk/chanvars.h"
 
 #include <unistd.h>
+#include <time.h>
 #include <setjmp.h>
 #if defined(__APPLE__)
 #include "asterisk/poll-compat.h"
@@ -235,8 +236,15 @@
 	/*! Original writer format */
 	int oldwriteformat;			
 	
-	/*! Timing fd */
+	/*! Timing fd for zaptel timers */
 	int timingfd;
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+	/*! POSIX timer id */
+	timer_t timerid;
+	int timerexpired;
+#endif
+	int timersavailable;
 	int (*timingfunc)(void *data);
 	void *timingdata;
 
--- /dev/null	2005-05-23 13:17:46.844591256 +0100
+++ timer.c	2005-05-24 11:18:17.000000000 +0100
@@ -0,0 +1,119 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Timer Management
+ * 
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * David Woodhouse <dwmw2 at infradead.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/options.h"
+#include "asterisk/timer.h"
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+static int timers_available = 0;
+
+void ast_check_posix_timers(void)
+{
+	struct timespec res;
+	int ret; 
+
+	ret = clock_getres(CLOCK_MONOTONIC, &res);
+
+	/* If CLOCK_MONOTONIC exists and has a resolution
+	   lower than 2ms, then use it. */
+	if (!ret && !res.tv_sec && res.tv_nsec > 2000000) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Using POSIX CLOCK_MONOTONIC with resolution %ld.%06ld ms\n",
+				res.tv_nsec / 1000000, res.tv_nsec % 1000000);
+		timers_available = 1;
+	} else if (!ret && option_debug) {
+		ast_log(LOG_DEBUG, "Not using POSIX CLOCK_MONOTONIC with insufficient resolution %ld.%06ld ms\n",
+			res.tv_sec*1000 + res.tv_nsec/1000000,
+			res.tv_nsec % 1000000);
+	} else if (option_debug) {
+		ast_log(LOG_DEBUG, "POSIX CLOCK_MONOTONIC unavailable\n");
+	}
+}
+
+void ast_channel_timer_expired(int signo, siginfo_t *info, void *ctx)
+{
+	struct ast_channel *chan = info->si_value.sival_ptr;
+
+	chan->timerexpired++;
+}
+#endif /* _POSIX_MONOTONIC_CLOCK */
+
+int ast_init_channel_timer(struct ast_channel *chan)
+{
+	chan->timersavailable = 0;
+	chan->timingfd = -1;
+
+#ifdef ZAPTEL_OPTIMIZATIONS
+	chan->timingfd = open("/dev/zap/timer", O_RDWR);
+	if (chan->timingfd > -1) {
+		/* Check if timing interface supports new
+		   ping/pong scheme */
+		int flags = 1;
+		chan->timersavailable = 1;
+
+		if (!ioctl(chan->timingfd, ZT_TIMERPONG, &flags))
+			return 1;
+	}
+#endif /* ZAPTEL_OPTIMIZATIONS */
+#ifdef _POSIX_MONOTONIC_CLOCK
+	chan->timerid = NO_TIMERID;
+	chan->timerexpired = 0;
+
+	if (timers_available) {
+		struct sigevent ev;
+		struct sigaction sa;
+		int res;
+
+		sa.sa_sigaction = &ast_channel_timer_expired;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_SIGINFO;
+
+		/* Make sure signal handler is set up */
+		res = sigaction(SIGRTMIN, &sa, NULL);
+		if (res) {
+			ast_log(LOG_WARNING, "Could not set handler for SIGRTMIN: %d\n", errno);
+			timers_available = 0;
+			return 0;
+		}
+		
+		/* Attempt to create POSIX timer for channel */
+		ev.sigev_value.sival_ptr = chan;
+		ev.sigev_signo = SIGRTMIN;
+		ev.sigev_notify = SIGEV_SIGNAL;
+
+		res = timer_create(CLOCK_MONOTONIC, &ev, &chan->timerid);
+		if (res) {
+			if (errno == EAGAIN) {
+				if (option_debug)
+					ast_log(LOG_DEBUG, "Could not create POSIX timer: EAGAIN\n");
+				return 0;
+			}
+			ast_log(LOG_WARNING, "Could not create POSIX timer: %d\n", errno);
+			timers_available = 0;
+			return 0;
+		}
+
+		/* Success */
+		chan->timersavailable = 1;
+		return 0;
+	}
+#endif /* _POSIX_MONOTONIC_CLOCK */
+	return 0;
+}
--- /dev/null	2005-05-23 13:17:46.844591256 +0100
+++ include/asterisk/timer.h	2005-05-24 11:16:39.000000000 +0100
@@ -0,0 +1,35 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Timer Management
+ * 
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * David Woodhouse <dwmw2 at infradead.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#ifndef __ASTERISK_TIMER_H__
+#define __ASTERISK_TIMER_H__
+
+#include <unistd.h>
+#include <time.h>
+
+#include "asterisk/channel.h"
+
+#ifndef _POSIX_MONOTONIC_CLOCK
+static inline int ast_check_posix_timers(void)
+{ }
+#else 
+
+#define NO_TIMERID ((timer_t)-1)
+
+void ast_check_posix_timers(void);
+int ast_init_channel_timer(struct ast_channel *chan);
+int ast_destroy_channel_timer(struct ast_channel *chan);
+#endif /* _POSIX_MONOTONIC_CLOCK */
+
+#endif /* __ASTERISK_TIMER_H__ */
+


-- 
dwmw2




More information about the asterisk-dev mailing list