Subject: Re: [linux-audio-dev] best method for timing
From: Paul Davis (pbd_AT_Op.Net)
Date: Tue Apr 16 2002 - 16:34:21 EEST
>I need to do some timing code - for some basic kind of sequencing..
>Since ive not written this kind of stuff before, i'm unsure as to the best app
>roach for accurate timing.
>
>I've played around with using signals for this - with setitimer(..) and then c
>atching the signal, but it doesnt look too good - it can be 1000s of usecs out
>..
>
>What approaches have people used, and how successful were they?
poll(2) on /dev/rtc. You will need to be root, or have CAP_RESOURCE,
to set the frequency of the clock to a useful value, and you will need
to run SCHED_FIFO to not have the kernel scheduler mess things up.
ardour and softwerk (which doesn't compile right now) both have code
for the RTC. In fact, I'll include ardour's below - its very simple
really. Any parts that are not clear are almost certainly not
necessary :)
alternatively, use the ALSA sequencer and/or timer APIs.
--p
/*
Copyright (C) 2001 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: rtc.h,v 1.1 2001/11/24 00:15:23 pbd Exp $
*/
#ifndef __ardour_rtc_h__
#define __ardour_rtc_h__
#include <pbd/thread.h>
#include <sigc++/signal_system.h>
class RealTimeClock : public QMThread, public SigC::Object
{
public:
RealTimeClock ();
virtual ~RealTimeClock();
bool set_interval (unsigned int usecs);
SigC::Signal0<void> tick;
private:
int rtc_fd;
int current_hz;
bool rtc_running;
bool start_periodic_interrupts ();
bool stop_periodic_interrupts ();
static void *start_thread (void *);
void *do_work ();
};
#endif /* __ardour_rtc_h__ */
/*
Copyright (C) 2001 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: rtc.cc,v 1.2 2002/04/10 17:42:57 pbd Exp $
*/
#include <stdio.h>
#include <linux/rtc.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <math.h>
#include <sys/ioctl.h>
#include <asm/timex.h>
#include <ardour/ardour.h>
#include <ardour/rtc.h>
using namespace ARDOUR;
RealTimeClock::RealTimeClock ()
: QMThread ("realtime clock", start_thread, this, true, 8)
{
if ((rtc_fd = open ("/dev/rtc", O_RDONLY)) < 0) {
error << "RealTimeClock: cannot open /dev/rtc ("
<< strerror (errno)
<< ')'
<< endmsg;
throw failed_constructor();
}
if (fcntl (rtc_fd, F_SETOWN, getpid()) < 0) {
error << "RealTimeClock: cannot set ownership of /dev/rtc ("
<< strerror (errno)
<< ')'
<< endmsg;
throw failed_constructor();
}
rtc_running = false;
current_hz = 0;
}
RealTimeClock::~RealTimeClock ()
{
stop_periodic_interrupts ();
close (rtc_fd);
}
void *
RealTimeClock::start_thread (void *arg)
{
RealTimeClock *rtc = (RealTimeClock *) arg;
return rtc->main ();
}
void *
RealTimeClock::do_work ()
{
unsigned long rtc_data;
start_periodic_interrupts ();
while (!work_no_more()) {
struct pollfd pfd;
pfd.fd = rtc_fd;
pfd.events = POLLIN | POLLERR;
if (poll (&pfd, 1, 100000) < 0) {
if (errno == EINTR) {
// this happens mostly when run
// under gdb, or when exiting due to a signal
continue;
}
error << "RealTimeClock: poll call failed ("
<< strerror (errno)
<< ')'
<< endmsg;
return (void *) -1;
}
read (rtc_fd, &rtc_data, sizeof (rtc_data));
tick ();
}
return 0;
}
bool
RealTimeClock::set_interval (guint32 usecs)
{
int req_hz = (int) floor ((1000000.0/usecs));
int hz = 2;
bool restart;
hz = 2;
while (hz < req_hz) {
hz *= 2;
}
if (hz == current_hz) {
return true;
}
restart = stop_periodic_interrupts ();
if (ioctl(rtc_fd, RTC_IRQP_SET, hz) < 0) {
error << "RealTimeClock: cannot set periodic interval ("
<< strerror (errno)
<< ')'
<< endmsg;
return -1;
}
current_hz = hz;
if (restart) {
start_periodic_interrupts ();
}
return true;
}
bool
RealTimeClock::start_periodic_interrupts ()
{
if (!rtc_running) {
if (ioctl (rtc_fd, RTC_PIE_ON, 0) < 0) {
error << "RealTimeClock: cannot start periodic interrupts ("
<< strerror (errno)
<< ')'
<< endmsg;
return false;
}
rtc_running = true;
}
return rtc_running;
}
bool
RealTimeClock::stop_periodic_interrupts ()
{
bool was_running = rtc_running;
if (rtc_running) {
if (ioctl (rtc_fd, RTC_PIE_OFF, 0) < 0) {
error << "RealTimeClock: cannot stop periodic interrupts ("
<< strerror (errno)
<< ')'
<< endmsg;
return rtc_running;
}
rtc_running = false;
}
return was_running;
}
This archive was generated by hypermail 2b28 : Tue Apr 16 2002 - 16:19:59 EEST