timer-posix.cpp revision cd35edfa8537ae28466f498e22b87190a852a574
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/* $Id$ */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** @file
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * InnoTek Portable Runtime - Timer, POSIX.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Copyright (C) 2006 InnoTek Systemberatung GmbH
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * available from http://www.virtualbox.org. This file is free software;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * General Public License as published by the Free Software Foundation,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * If you received this file as part of a commercial VirtualBox
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * distribution, then only the terms of your commercial VirtualBox
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * license agreement apply instead of the previous paragraph.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync* Header Files *
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync*******************************************************************************/
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync#include <iprt/timer.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/alloc.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/assert.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/thread.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/log.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/asm.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/semaphore.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/string.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/err.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <unistd.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <sys/fcntl.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <sys/ioctl.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef __LINUX__
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <linux/rtc.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <sys/time.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <signal.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <errno.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifndef __OS2__
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <pthread.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Structures and Typedefs *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * The internal representation of a timer handle.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsynctypedef struct RTTIMER
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Magic.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This is RTTIMER_MAGIC, but changes to something else before the timer
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * is destroyed to indicate clearly that thread should exit. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync volatile uint32_t u32Magic;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Win32 timer id. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTTHREAD Thread;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** User argument. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync void *pvUser;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Callback. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync PFNRTTIMER pfnTimer;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** The timeout values for the timer. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync struct itimerval TimerVal;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** The error/status of the timer.
c62d2520ac91e12cf4665c936f490dd2064152d3vboxsync * Initially -1, set to 0 when the timer have been successfully started, and
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * to errno on failure in starting the timer. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync volatile int iError;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync} RTTIMER;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Timer handle magic. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#define RTTIMER_MAGIC 0x42424242
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Signal handler which ignore everything it gets.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param iSignal The signal number.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rttimerSignalIgnore(int iSignal)
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync{
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync //AssertBreakpoint();
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync}
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync/**
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * SIGALRM wait thread.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsyncstatic DECLCALLBACK(int) rttimerThread(RTTHREAD Thread, void *pvArg)
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync{
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync PRTTIMER pTimer = (PRTTIMER)(void *)pvArg;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync RTTIMER Timer = *pTimer;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync Assert(pTimer->u32Magic == RTTIMER_MAGIC);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
c62d2520ac91e12cf4665c936f490dd2064152d3vboxsync /*
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Install signal handler.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync struct sigaction SigAct;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync memset(&SigAct, 0, sizeof(SigAct));
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync SigAct.sa_flags = SA_RESTART;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigemptyset(&SigAct.sa_mask);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync SigAct.sa_handler = rttimerSignalIgnore;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync if (sigaction(SIGALRM, &SigAct, NULL))
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync {
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync SigAct.sa_flags &= ~SA_RESTART;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync if (sigaction(SIGALRM, &SigAct, NULL))
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync AssertMsgFailed(("sigaction failed, errno=%d\n", errno));
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync }
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /*
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * Mask most signals except those which might be used during
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * termination is by a pthread implementation.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync sigset_t SigSet;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigfillset(&SigSet);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigdelset(&SigSet, SIGTERM);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigdelset(&SigSet, SIGHUP);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigdelset(&SigSet, SIGINT);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigdelset(&SigSet, SIGABRT);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigdelset(&SigSet, SIGKILL);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync#ifdef SIGRTMIN
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync for (int iSig = SIGRTMIN; iSig < SIGRTMAX; iSig++)
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync sigdelset(&SigSet, iSig);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync#endif
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync if (sigprocmask(SIG_SETMASK, &SigSet, NULL))
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync {
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync int rc = pTimer->iError = RTErrConvertFromErrno(errno);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync AssertMsgFailed(("sigprocmask -> errno=%d\n", errno));
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync return rc;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync }
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /*
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Start the timer.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync *
56602ba12f2388501d594c83fbbf77b4b16f8f4fvboxsync * For some SunOS (/SysV?) threading compatibility Linux will only
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * deliver the SIGALRM to the thread calling setitimer(). Therefore
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * we have to call it here.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync *
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * It turns out this might not always be the case, see SIGALRM killing
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * processes on RH 2.4.21.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync if (setitimer(ITIMER_REAL, &pTimer->TimerVal, NULL))
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync {
56602ba12f2388501d594c83fbbf77b4b16f8f4fvboxsync pTimer->iError = RTErrConvertFromErrno(errno);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync RTThreadUserSignal(Thread);
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync return errno;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync }
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /*
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Signal wait loop-forever.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync sigemptyset(&SigSet);
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync sigaddset(&SigSet, SIGALRM);
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync RTThreadUserSignal(Thread);
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync while (pTimer->u32Magic == RTTIMER_MAGIC)
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync {
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync siginfo_t SigInfo = {0};
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef __DARWIN__
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (sigwait(&SigSet, &SigInfo.si_signo) >= 0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
c62d2520ac91e12cf4665c936f490dd2064152d3vboxsync#else
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync if (sigwaitinfo(&SigSet, &SigInfo) >= 0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( SigInfo.si_signo == SIGALRM
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pTimer->u32Magic == RTTIMER_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else if (errno != EINTR)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("sigwaitinfo -> errno=%d\n", errno));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Disable the timer.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync struct itimerval TimerVal = {{0,0}, {0,0}};
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (setitimer(ITIMER_REAL, &TimerVal, NULL))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("setitimer(ITIMER_REAL,&{0}, NULL) failed, errno=%d\n", errno));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Exit.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTThreadUserSignal(Thread);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Create a recurring timer.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * @returns iprt status code.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * @param ppTimer Where to store the timer handle.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * @param uMilliesInterval Milliseconds between the timer ticks.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * This is rounded up to the system granularity.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * @param pfnCallback Callback function which shall be scheduled for execution
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * on every timer tick.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * @param pvUser User argument for the callback.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsyncRTR3DECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser)
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync{
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Check if timer is busy.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync struct itimerval TimerVal;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (getitimer(ITIMER_REAL, &TimerVal))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("getitimer() -> errno=%d\n", errno));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VERR_NOT_IMPLEMENTED;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( TimerVal.it_value.tv_usec || TimerVal.it_value.tv_sec
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || TimerVal.it_interval.tv_usec || TimerVal.it_interval.tv_sec
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync )
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("A timer is running. System limit is one timer per process!\n"));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VERR_TIMER_BUSY;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Block SIGALRM from calling thread.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync sighold(SIGALRM);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync static bool fDoneRTC;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!fDoneRTC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync fDoneRTC = true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* check resolution. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync TimerVal.it_interval.tv_sec = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync TimerVal.it_interval.tv_usec = 1000;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync TimerVal.it_value = TimerVal.it_interval;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( setitimer(ITIMER_REAL, &TimerVal, NULL)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || getitimer(ITIMER_REAL, &TimerVal)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || TimerVal.it_interval.tv_usec > 1000)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Try open /dev/rtc to set the irq rate to 1024 and
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * turn periodic
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Log(("RTTimerCreate: interval={%ld,%ld} trying to adjust /dev/rtc!\n", TimerVal.it_interval.tv_sec, TimerVal.it_interval.tv_usec));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef __LINUX__
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int fh = open("/dev/rtc", O_RDONLY);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (fh >= 0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( ioctl(fh, RTC_IRQP_SET, 1024) < 0
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || ioctl(fh, RTC_PIE_ON, 0) < 0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Log(("RTTimerCreate: couldn't configure rtc! errno=%d\n", errno));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ioctl(fh, F_SETFL, O_ASYNC);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ioctl(fh, F_SETOWN, getpid());
c62d2520ac91e12cf4665c936f490dd2064152d3vboxsync /* not so sure if closing it is a good idea... */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync //close(fh);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Log(("RTTimerCreate: couldn't configure rtc! open failed with errno=%d\n", errno));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* disable it */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync TimerVal.it_interval.tv_sec = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync TimerVal.it_interval.tv_usec = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync TimerVal.it_value = TimerVal.it_interval;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync setitimer(ITIMER_REAL, &TimerVal, NULL);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Create new timer.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pTimer)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->u32Magic = RTTIMER_MAGIC;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->iError = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->pvUser = pvUser;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->pfnTimer = pfnTimer;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->TimerVal.it_interval.tv_sec = uMilliesInterval / 1000;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->TimerVal.it_interval.tv_usec = (uMilliesInterval % 1000) * 1000;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pTimer->TimerVal.it_value = pTimer->TimerVal.it_interval;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = RTThreadCreate(&pTimer->Thread, rttimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_SUCCESS(rc))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Wait for the timer to successfully create the timer
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** @todo something is may cause this to take very long. We're waiting 30 seconds now and hope that'll workaround it... */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = RTThreadUserWait(pTimer->Thread, 30*1000);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_SUCCESS(rc))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = pTimer->iError;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_SUCCESS(rc))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTThreadYield(); /* Horrible hack to make tstTimer work. Something is really fucked related to scheduling here! (2.6.12) */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *ppTimer = pTimer;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("Failed to create timer uMilliesInterval=%d. rc=%Vrc\n", uMilliesInterval, rc));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTMemFree(pTimer);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = VERR_NO_MEMORY;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Stops and destroys a running timer.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns iprt status code.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pTimer Timer to stop and destroy.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTR3DECL(int) RTTimerDestroy(PRTTIMER pTimer)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync LogFlow(("RTTimerDestroy: pTimer=%p\n", pTimer));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* NULL is ok. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pTimer)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Validate input.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (VALID_PTR(pTimer))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Modify the magic and kick it.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1) == RTTIMER_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifndef __OS2__
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pthread_kill((pthread_t)RTThreadGetNative(pTimer->Thread), SIGALRM);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Wait for the thread to exit.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = RTThreadWait(pTimer->Thread, 30 * 1000, NULL);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( RT_SUCCESS(rc)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || rc == VERR_INVALID_HANDLE /* we don't keep handles around, you gotta wait before it really exits! */)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTMemFree(pTimer);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("Failed to destroy timer %p. rc=%Vrc\n", pTimer, rc));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("Timer %p is already being destroyed!\n", pTimer));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = VERR_INVALID_MAGIC;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("Bad pTimer pointer %p!\n", pTimer));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = VERR_INVALID_HANDLE;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync