/*
  XBubble - timer.c
 
  Copyright (C) 2002  Ivan Djelic <ivan@savannah.gnu.org>
  
  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
*/

#include <stdio.h>
#include <stdlib.h> /* exit */
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>

#include "timer.h"

struct timeval interval;
extern int fps;

/*
  I couldn't find a portable way to get the actual interval timer
  resolution; typical values are:
  * ix86  : 10 ms
  * alpha : 1 ms
  So I'll stick to a 10ms resolution. If you've got an Alpha CPU you can
  probably set ITIMER_RESOLUTION to 1000.
*/

#define ITIMER_RESOLUTION  10000

long get_closest_itimer_interval( long usec ) {
  if ( usec % ITIMER_RESOLUTION )
    return ( usec/ITIMER_RESOLUTION + 1 )*ITIMER_RESOLUTION;
  return usec;
}

void start_timer( long usec, void (*handler)(int)) {
  struct sigaction action;
  struct itimerval value;
  
  /* setup interval timer */
  interval.tv_sec = 0;
  interval.tv_usec = usec;
  value.it_interval = interval;
  value.it_value = interval;
  
  /* prepare for catching SIGALRM signal */
  action.sa_handler = handler;
  action.sa_flags = 0;
  sigemptyset(&(action.sa_mask));
  
  if (( sigaction( SIGALRM, &action, NULL ) != 0 )||
      ( setitimer( ITIMER_REAL, &value, NULL) < 0 )) {
    perror( "start_timer");
    exit(1);
  }
}

void stop_timer() {
  struct itimerval value;
  interval.tv_sec = 0;
  interval.tv_usec = 0;
  value.it_interval = interval;
  value.it_value = interval;
  setitimer( ITIMER_REAL, &value, NULL);
}

void timer_sleep( long ms ) {
  long i;
  for ( i = ms*fps/1000; i > 0; i-- )
    pause();
}

void block_timer() {
  sigset_t set;
  sigemptyset( &set );
  sigaddset( &set, SIGALRM );
  sigprocmask( SIG_BLOCK, &set, NULL );
}

void unblock_timer() {
  sigset_t set;
  sigemptyset( &set );
  sigaddset( &set, SIGALRM );
  sigprocmask( SIG_UNBLOCK, &set, NULL );
}
