linapple-pie/src/Timer.cpp

238 lines
5.8 KiB
C++

/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Description: Core sound related functionality
*
* Author: Tom Charlesworth
*/
/* Adaption for Linux+SDL done by beom beotiger. Peace! LLL */
// Timers like functions for Windows and Posix
// for usleep()
#include <unistd.h>
#include "stdafx.h"
#include "Timer.h"
#ifndef _WIN32
//for Timers try to use POSIX compliant timers
#include <signal.h>
#include <sys/time.h>
#endif
// for Assertion
#include <assert.h>
#ifndef _WIN32
//===============================================================================//
// Timer Functions - POSIX specific //
//=============================================================================//
// Vars
static bool g_bRefClockTimerActive = false;
static DWORD g_dwLastUsecPeriod = 0;
static bool g_bTimerToggle = false;
struct sigaction sa_SysClk;
struct itimerval mytimeset;
void SysClk_TickTimer(int signum)
{ // should occur every specified times per second
g_bTimerToggle = true; // just set the toggle flag, and leave peacefully? --bb
}
bool SysClk_InitTimer()
{// first initialization of the timer
/* memset(&sa_SysClk, 0, sizeof(sa_SysClk)); // clear sigaction struct
sa_SysClk.sa_handler = &SysClk_TickTimer;
sigaction(SIGALRM, &sa_SysClk, NULL); // set SIGALRM handler*/
if(signal(SIGALRM, SysClk_TickTimer) == SIG_ERR)
return false;
printf("Timer has been initted!\n");
return true;
}
void SysClk_UninitTimer()
{
SysClk_StopTimer();
// signal(SIGALRM, NULL);
}
void SysClk_WaitTimer()
{
// printf("Waiting timer...\n");
if(!g_bRefClockTimerActive)
return;
// pause() - better than that?
while(!g_bTimerToggle)
usleep(1); // do nothing is something doing also? 0_0 --bb
g_bTimerToggle = false;
// printf("Timer has been ticked!\n");
}
void SysClk_StartTimerUsec(DWORD dwUsecPeriod)
{
// starting timer during dwUsecPeriod in microseconds???
// printf("Timer started %d usec\n", dwUsecPeriod);
if(g_bRefClockTimerActive && (g_dwLastUsecPeriod == dwUsecPeriod))
return;
SysClk_StopTimer();
// to comply with Windows DirectShow REFERENCE_TIME, which is in units of 100 nanoseconds
mytimeset.it_interval.tv_sec = 0;
mytimeset.it_interval.tv_usec = dwUsecPeriod;// * 10 100;
mytimeset.it_value.tv_sec = 0;
mytimeset.it_value.tv_usec = dwUsecPeriod;// * 10 / 100;
if(setitimer(ITIMER_REAL, &mytimeset, NULL) != 0) {
fprintf(stderr, "Error creating timer (setitimer failed)\n");
_ASSERT(0);
return;
}
g_dwLastUsecPeriod = dwUsecPeriod;
g_bRefClockTimerActive = true;
}
void SysClk_StopTimer()
{
if(!g_bRefClockTimerActive)
return;
// Zero values just disables timers
mytimeset.it_interval.tv_sec = 0;
mytimeset.it_interval.tv_usec = 0;
mytimeset.it_value.tv_sec = 0;
mytimeset.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &mytimeset, NULL);
g_bTimerToggle = true;
g_bRefClockTimerActive = false;
}
#else
//===============================================================================//
// Timer Functions - WINDOWS specific //
//===============================================================================//
// Vars
static DWORD g_dwAdviseToken;
static IReferenceClock *g_pRefClock = NULL;
static HANDLE g_hSemaphore = NULL;
static bool g_bRefClockTimerActive = false;
static DWORD g_dwLastUsecPeriod = 0;
bool SysClk_InitTimer()
{
g_hSemaphore = CreateSemaphore(NULL, 0, 1, NULL); // Max count = 1
if (g_hSemaphore == NULL)
{
fprintf(stderr, "Error creating semaphore\n");
return false;
}
if (CoCreateInstance(CLSID_SystemClock, NULL, CLSCTX_INPROC,
IID_IReferenceClock, (LPVOID*)&g_pRefClock) != S_OK)
{
fprintf(stderr, "Error initialising COM\n");
return false; // Fails for Win95!
}
return true;
}
void SysClk_UninitTimer()
{
SysClk_StopTimer();
SAFE_RELEASE(g_pRefClock);
if (CloseHandle(g_hSemaphore) == 0)
fprintf(stderr, "Error closing semaphore handle\n");
}
//
void SysClk_WaitTimer()
{
if(!g_bRefClockTimerActive)
return;
WaitForSingleObject(g_hSemaphore, INFINITE);
}
void SysClk_StartTimerUsec(DWORD dwUsecPeriod)
{
if(g_bRefClockTimerActive && (g_dwLastUsecPeriod == dwUsecPeriod))
return;
SysClk_StopTimer();
REFERENCE_TIME rtPeriod = (REFERENCE_TIME) (dwUsecPeriod * 10); // In units of 100ns
REFERENCE_TIME rtNow;
HRESULT hr = g_pRefClock->GetTime(&rtNow);
// S_FALSE : Returned time is the same as the previous value
if ((hr != S_OK) && (hr != S_FALSE))
{
fprintf(stderr, "Error creating timer (GetTime failed)\n");
_ASSERT(0);
return;
}
if (g_pRefClock->AdvisePeriodic(rtNow, rtPeriod, g_hSemaphore, &g_dwAdviseToken) != S_OK)
{
fprintf(stderr, "Error creating timer (AdvisePeriodic failed)\n");
_ASSERT(0);
return;
}
g_dwLastUsecPeriod = dwUsecPeriod;
g_bRefClockTimerActive = true;
}
void SysClk_StopTimer()
{
if(!g_bRefClockTimerActive)
return;
if (g_pRefClock->Unadvise(g_dwAdviseToken) != S_OK)
{
fprintf(stderr, "Error deleting timer\n");
_ASSERT(0);
return;
}
g_bRefClockTimerActive = false;
}
#endif