linux: Use timerfd instead of poll timeouts

Günther Brammer 2011-03-15 17:27:10 +01:00
parent acac8a01d4
commit 8036211c30
8 changed files with 168 additions and 88 deletions

View File

@ -676,6 +676,7 @@ CHECK_INCLUDE_FILE_CXX(execinfo.h HAVE_EXECINFO_H)
CHECK_INCLUDE_FILE_CXX(langinfo.h HAVE_LANGINFO_H)
CHECK_INCLUDE_FILE_CXX(poll.h HAVE_POLL_H)
CHECK_INCLUDE_FILE_CXX(sys/inotify.h HAVE_SYS_INOTIFY_H)
CHECK_INCLUDE_FILE_CXX(sys/timerfd.h HAVE_SYS_TIMERFD_H)
CHECK_INCLUDE_FILE_CXX(sys/socket.h HAVE_SYS_SOCKET_H)
CHECK_INCLUDE_FILE_CXX(sys/file.h HAVE_SYS_FILE_H)
if(USE_CONSOLE)

View File

@ -103,6 +103,9 @@
/* Define to 1 if you have the <sys/syscall.h> header file. */
#cmakedefine HAVE_SYS_SYSCALL_H 1
/* Define to 1 if you have the <sys/timerfd.h> header file. */
#cmakedefine HAVE_SYS_TIMERFD_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H 1

View File

@ -105,6 +105,9 @@
/* Define to 1 if you have the <sys/syscall.h> header file. */
#undef HAVE_SYS_SYSCALL_H
/* Define to 1 if you have the <sys/timerfd.h> header file. */
#undef HAVE_SYS_TIMERFD_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H

View File

@ -56,7 +56,7 @@ AM_CONDITIONAL(MACOSX, [test $osx = true])
# various used headers
dnl the whitespace is there to prevent AC_INCLUDES_DEFAULT
AC_CHECK_HEADERS([stdint.h unistd.h poll.h sys/file.h sys/stat.h sys/types.h locale.h sys/socket.h signal.h langinfo.h sys/inotify.h sys/syscall.h], , , [[ ]])
AC_CHECK_HEADERS([stdint.h unistd.h poll.h sys/file.h sys/stat.h sys/types.h locale.h sys/socket.h signal.h langinfo.h sys/timerfd.h sys/inotify.h sys/syscall.h], , , [[ ]])
# Mingw does not ship with multimon.h
AC_CHECK_HEADERS([multimon.h io.h direct.h share.h], [], [], [[#include <windows.h>]])
# iconv

View File

@ -572,3 +572,114 @@ bool CStdNotifyProc::CheckAndReset()
return r;
}
#endif
/* CStdMultimediaTimerProc */
#ifdef STDSCHEDULER_USE_EVENTS
int CStdMultimediaTimerProc::iTimePeriod = 0;
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay) :
uCriticalTimerDelay(28),
idCriticalTimer(0),
uCriticalTimerResolution(5),
Event(true)
{
if (!iTimePeriod)
{
// Get resolution caps
TIMECAPS tc;
timeGetDevCaps(&tc, sizeof(tc));
// Establish minimum resolution
uCriticalTimerResolution = BoundBy(uCriticalTimerResolution, tc.wPeriodMin, tc.wPeriodMax);
timeBeginPeriod(uCriticalTimerResolution);
}
iTimePeriod++;
SetDelay(iDelay);
}
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
{
if (idCriticalTimer)
{
timeKillEvent(idCriticalTimer);
idCriticalTimer = 0;
iTimePeriod--;
if (!iTimePeriod)
timeEndPeriod(uCriticalTimerResolution);
}
}
void CStdMultimediaTimerProc::SetDelay(uint32_t iDelay)
{
// Kill old timer (of any)
if (idCriticalTimer)
timeKillEvent(idCriticalTimer);
// Set critical timer
idCriticalTimer=timeSetEvent(
uCriticalTimerDelay,uCriticalTimerResolution,
(LPTIMECALLBACK) Event.GetEvent(),0,TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
}
bool CStdMultimediaTimerProc::CheckAndReset()
{
if (!Check()) return false;
Event.Reset();
return true;
}
#elif defined(HAVE_SYS_TIMERFD_H)
#include <sys/timerfd.h>
#include <unistd.h>
#include <fcntl.h>
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay)
{
// FIXME: Once linux version 2.6.27 is required, use TFD_NONBLOCK and TFD_CLOEXEC
fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (fd == -1)
Log("timerfd_create failed");
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
fcntl(fd, F_SETFD, FD_CLOEXEC);
SetDelay(iDelay);
}
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
{
close(fd);
}
void CStdMultimediaTimerProc::SetDelay(uint32_t inDelay)
{
struct itimerspec nv, ov;
nv.it_interval.tv_sec = inDelay / 1000;
nv.it_interval.tv_nsec = (inDelay % 1000) * 1000000;
nv.it_value = nv.it_interval;
timerfd_settime(fd, 0, &nv, &ov);
}
void CStdMultimediaTimerProc::Set()
{
struct itimerspec nv, ov;
timerfd_gettime(fd, &nv);
nv.it_value.tv_sec = 0;
nv.it_value.tv_nsec = 1;
timerfd_settime(fd, 0, &nv, &ov);
}
bool CStdMultimediaTimerProc::CheckAndReset()
{
uint64_t n;
return read(fd, &n, 8) != -1;
}
void CStdMultimediaTimerProc::GetFDs(std::vector<struct pollfd> & checkfds)
{
pollfd pfd = { fd, POLLIN, 0 };
checkfds.push_back(pfd);
}
#endif

View File

@ -150,6 +150,55 @@ public:
#endif
};
#ifdef STDSCHEDULER_USE_EVENTS
class CStdMultimediaTimerProc : public CStdNotifyProc
{
public:
CStdMultimediaTimerProc(uint32_t iDelay);
~CStdMultimediaTimerProc();
private:
static int iTimePeriod;
uint32_t uCriticalTimerDelay;
UINT idCriticalTimer,uCriticalTimerResolution;
CStdEvent Event;
bool Check() { return Event.WaitFor(0); }
public:
void SetDelay(uint32_t iDelay);
void Set() { Event.Set(); }
bool CheckAndReset();
// StdSchedulerProc overrides
virtual HANDLE GetEvent() { return Event.GetEvent(); }
};
#elif defined(HAVE_SYS_TIMERFD_H)
// timer proc using a timerfd
class CStdMultimediaTimerProc : public StdSchedulerProc
{
public:
CStdMultimediaTimerProc(uint32_t iDelay);
~CStdMultimediaTimerProc();
private:
int fd;
public:
void Set();
void SetDelay(uint32_t inDelay);
bool CheckAndReset();
// StdSchedulerProc overrides
virtual void GetFDs(std::vector<struct pollfd> & checkfds);
};
#else
#define CStdMultimediaTimerProc CStdTimerProc
#endif
// A simple process scheduler
class StdScheduler
{

View File

@ -217,66 +217,6 @@ void CStdWindow::EnumerateMultiSamples(std::vector<int>& samples) const
#endif
}
/* CStdTimerProc */
int CStdMultimediaTimerProc::iTimePeriod = 0;
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay) :
uCriticalTimerDelay(28),
idCriticalTimer(0),
uCriticalTimerResolution(5),
Event(true)
{
if (!iTimePeriod)
{
// Get resolution caps
TIMECAPS tc;
timeGetDevCaps(&tc, sizeof(tc));
// Establish minimum resolution
uCriticalTimerResolution = BoundBy(uCriticalTimerResolution, tc.wPeriodMin, tc.wPeriodMax);
timeBeginPeriod(uCriticalTimerResolution);
}
iTimePeriod++;
SetDelay(iDelay);
}
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
{
if (idCriticalTimer)
{
timeKillEvent(idCriticalTimer);
idCriticalTimer = 0;
iTimePeriod--;
if (!iTimePeriod)
timeEndPeriod(uCriticalTimerResolution);
}
}
void CStdMultimediaTimerProc::SetDelay(uint32_t iDelay)
{
// Kill old timer (of any)
if (idCriticalTimer)
timeKillEvent(idCriticalTimer);
// Set critical timer
idCriticalTimer=timeSetEvent(
uCriticalTimerDelay,uCriticalTimerResolution,
(LPTIMECALLBACK) Event.GetEvent(),0,TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
}
bool CStdMultimediaTimerProc::CheckAndReset()
{
if (!Check()) return false;
Event.Reset();
return true;
}
/* CStdMessageProc */
bool CStdMessageProc::Execute(int iTimeout, pollfd *)

View File

@ -369,31 +369,6 @@ public:
};
#ifdef _WIN32
class CStdMultimediaTimerProc : public CStdNotifyProc
{
public:
CStdMultimediaTimerProc(uint32_t iDelay);
~CStdMultimediaTimerProc();
private:
static int iTimePeriod;
uint32_t uCriticalTimerDelay;
UINT idCriticalTimer,uCriticalTimerResolution;
CStdEvent Event;
public:
void SetDelay(uint32_t iDelay);
void Set() { Event.Set(); }
bool Check() { return Event.WaitFor(0); }
bool CheckAndReset();
// StdSchedulerProc overrides
virtual HANDLE GetEvent() { return Event.GetEvent(); }
};
class CStdMessageProc : public StdSchedulerProc
{
public:
@ -411,8 +386,6 @@ public:
virtual HANDLE GetEvent() { return STDSCHEDULER_EVENT_MESSAGE; }
};
#else
#define CStdMultimediaTimerProc CStdTimerProc
#endif
#ifdef USE_CONSOLE