Logo Search packages:      
Sourcecode: bb version File versions  Download package

timers.c

/* 
 *     XaoS, a fast portable realtime fractal zoomer 
 *                  Copyright (C) 1996,1997 by
 *
 *      Jan Hubicka          (hubicka@paru.cas.cz)
 *      Thomas Marsh         (tmarsh@austin.ibm.com)
 *
 * 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.
 *
 * All ugly architecture depended timing code is separated into this file..
 */
#ifdef _plan9_
#include <u.h>
#include <stdio.h>
#include <libc.h>
#else
#include "aconfig.h"
#ifdef HAVE_GETTIMEOFDAY
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif 
   /*HAVE_UNISTD*/
#else
#ifdef HAVE_FTIME
#include <sys/timeb.h>
#endif
   /*HAVE_FTIME*/
#endif
   /*HAVE_GETTIMEOFDAY*/
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
   /*HAVE_TIME_H*/
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#ifndef _MAC
#include <malloc.h>
#endif
#ifdef __BEOS__
#include <OS.h>
#endif
#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#ifdef HAVE_SETITIMER
#include <signal.h>
#endif
#include <limits.h>
#endif
#ifndef _plan9_
#include <assert.h>
#endif
#include "timers.h"
#ifdef _WIN32
#include <windows.h>
#endif

#ifdef _WIN32
#define QuadPart(x) (((long long)x.HighPart << 32) + x.LowPart)
#endif

#define EMULDIV 1024
struct timeemulator
{
  unsigned long int time;
  unsigned long exact;
};

  /* Definition of structure timer. There is lots of various formats for time
   * at variious platforms. So there is quite lots of ifdefs... same is for
   * saving current time and function comparing them. Rest of timer lib
   * is platform independent
   */


struct timer
  {
#ifdef __BEOS__
bigtime_t lastactivated;
#else
#ifdef _WIN32
LARGE_INTEGER lastactivated;
#else
#ifdef USE_ALLEGRO
    uclock_t lastactivated;
#else
#ifdef HAVE_UCLOCK
    uclock_t lastactivated;
#else
#ifdef USE_CLOCK
    int lastactivated;
#else
#ifdef HAVE_GETTIMEOFDAY
    struct timeval lastactivated;
#else
#ifdef _plan9_
    int lastactivated;
#else
#ifdef HAVE_FTIME
    struct timeb lastactivated;
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
    unsigned long lastemulated;
    struct timeemulator *emulator;
    void (*handler) (void *);
    void (*multihandler) (void *, int);
    void *userdata;
    struct timer *next, *previous, *group;
    int interval;
    int stopped;
    int stoppedtime;
    int slowdown;
  };

                                  /*Variable for saving current time*/
#ifdef __BEOS__
bigtime_t currenttime;
#else
#ifdef _WIN32
LARGE_INTEGER currenttime,frequency;
#else
#ifdef USE_ALLEGRO
int allegromode;
#define TICKSPERSEC 100       /*must be divisor of 1000000 */
volatile static int counter = -1;
static int ainstalled;
#endif
#ifdef HAVE_UCLOCK
static uclock_t currenttime;
#else
#ifdef USE_CLOCK
static int currenttime;
#else
#ifdef HAVE_GETTIMEOFDAY
static struct timeval currenttime;
#ifdef AMIGA
extern long __timezone;
#define tzp __timezone
#else
static struct timezone tzp;
#endif
#else
#ifdef HAVE_FTIME
static struct timeb currenttime;
#endif
#endif
#endif
#endif
#ifdef _plan9_
static int currenttime;
#endif
#endif
#endif

#ifdef HAVE_SETITIMER
static int registered = 0, reghandler = 0;
static tl_group group2;
#endif
static tl_group group1;
tl_group *syncgroup = &group1,
#ifdef HAVE_SETITIMER
 *asyncgroup = &group2;
#else
 *asyncgroup = &group1;
#endif
#ifdef _plan9_
static int
plan9_msec (void)
{                       /*this function was sent by Nigel Roles */
  static int fd = -1;
  char buf[20];               /* ish */
  if (fd < 0)
    fd = open ("/dev/msec", OREAD);
  else
    seek (fd, 0, 0);
  read (fd, buf, sizeof (buf));
  return atoi (buf);
}
#endif

#ifndef __BEOS__
#ifndef _WIN32
#ifndef HAVE_GETTIMEOFDAY
#ifndef HAVE_FTIME
#ifndef _plan9_
#error I am unable to get time in milisecond. Please edit timers.c and make tl_update_time and tl_lookup_timer to work for your architecture and send me then back(to hubicka@paru.cas.cz). You will need also define timers.h and change type of lasttime.
#endif
#endif
#endif
#endif
#endif


#ifdef USE_ALLEGRO
static void
timer (void)
{
  counter++;
}
END_OF_FUNCTION (timer);
#endif
/*following functions are architecture dependent */
void
tl_update_time (void)
{
#ifdef __BEOS__
 currenttime=system_time();
#else
#ifdef _WIN32
  QueryPerformanceCounter (&currenttime);
#else
#ifdef USE_ALLEGRO
  if (allegromode)
    {
      if (counter == -1)
      {
        LOCK_VARIABLE (counter);
        LOCK_FUNCTION (timer);
        install_int (timer, 1000 / TICKSPERSEC);
        ainstalled = 1;
        counter = 0;
      }
      currenttime = counter;
      return;
    }
#endif
#ifdef HAVE_UCLOCK
  currenttime = uclock ();
#else
#ifdef USE_CLOCK
  currenttime = clock ();
#else
#ifdef HAVE_GETTIMEOFDAY
  do
    {
      gettimeofday (&currenttime, &tzp);
    }
  while (currenttime.tv_usec > 999999);
#else
#ifdef HAVE_FTIME
  ftime (&currenttime);
#endif
#endif
#endif
#endif
#endif
#endif
#ifdef _plan9_
  currenttime = plan9_msec ();
#endif
}

static INLINE int
__lookup_timer (tl_timer * t)
{
#ifdef __BEOS__
      return (currenttime - t->lastactivated);
#else
#ifdef _WIN32
      return ((QuadPart(currenttime) - QuadPart(t->lastactivated)) * 1000000LL) / QuadPart(frequency);
#else
#ifdef USE_ALLEGRO
  if (allegromode)
    return (((currenttime - t->lastactivated) * (1000000LL / TICKSPERSEC)));
#endif
#ifdef HAVE_UCLOCK
  return (((currenttime - t->lastactivated) * 1000000LL) / UCLOCKS_PER_SEC);
#else
#ifdef USE_CLOCK
  return ((currenttime - t->lastactivated) * (1000000.0 / CLOCKS_PER_SEC));
#else
#ifdef HAVE_GETTIMEOFDAY
  return ((1000000 * (-(int)t->lastactivated.tv_sec + (int)currenttime.tv_sec) + (-(int)t->lastactivated.tv_usec + (int)currenttime.tv_usec)));
#else
#ifdef HAVE_FTIME
  return ((1000000 * (-t->lastactivated.time + currenttime.time) + 1000 * (-t->lastactivated.millitm + currenttime.millitm)));
#else
#ifdef _plan9_
  return ((currenttime - t->lastactivated) * 1000);
#endif
#endif
#endif
#endif
#endif
#endif
#endif
}
int
tl_lookup_timer (tl_timer * t)
{
  if (t->stopped)
    {
      return (t->stoppedtime);
    }
  if (t->emulator!=NULL)
  {
    return((int)(t->emulator->time-t->lastemulated)*EMULDIV);
  }
  return (__lookup_timer (t) - t->slowdown);
}
void
tl_stop_timer (tl_timer * t)
{
  if (!t->stopped)
    {
      t->stoppedtime = tl_lookup_timer (t);
      t->stopped = 1;
    }
}
void
tl_slowdown_timer (tl_timer * t, int time)
{
  if (!t->stopped)
    {
      t->slowdown += time;
    }
  else
    t->stoppedtime -= time;
}
void
tl_resume_timer (tl_timer * t)
{
  if (t->stopped)
    {
      t->stopped = 0;
      t->slowdown = tl_lookup_timer (t) - t->stoppedtime;
    }
}
void
tl_sleep (int time)
{
#ifdef _WIN32
  Sleep (time/1000);
#else
#ifdef HAVE_USLEEP
  usleep (time);
#else
#ifdef __BEOS__
  snooze(time);
#else
#ifdef HAVE_SELECT
  {
    struct timeval tv;
    tv.tv_sec = time / 1000000L;
    tv.tv_usec = time % 1000000L;
    (void) select (0, (void *) 0, (void *) 0, (void *) 0, &tv);
  }
#else
#ifdef _plan9_
  sleep (time / 1000);
#else
/*
   #warning tl_sleep function not implemented. You may ignore this warning.
   #warning xaos will work correctly. But on miltitasked enviroments it is
   #warning HIGHLY recomended to implement this.
 */
#endif
#endif
#endif
#endif
#endif
}

void
tl_reset_timer (tl_timer * t)
{
  tl_update_time();
  if (t->stopped)
    t->stoppedtime = 0;
  else {
  if (t->emulator!=NULL)
  {
    t->lastemulated=t->emulator->time;
  } else
    t->lastactivated = currenttime,
    t->slowdown = 0;
  }
}

tl_timer *
tl_create_timer (void)
{
  tl_timer *timer;
  timer = (tl_timer *) calloc (1, sizeof (tl_timer));
  if (timer == NULL)
    return NULL;
  timer->interval = -1;
  timer->handler = NULL;
  timer->multihandler = NULL;
  timer->userdata = NULL;
  timer->next = NULL;
  timer->previous = NULL;
  timer->group = NULL;
  timer->stopped = 0;
  timer->stoppedtime = 0;
  timer->slowdown = 0;
  timer->emulator = NULL;
  tl_reset_timer (timer);
#ifdef _WIN32
  QueryPerformanceFrequency (&frequency);
#endif
  return (timer);
}
tl_group *
tl_create_group (void)
{
  tl_group *timer;
  timer = (tl_group *) calloc (1, sizeof (tl_group));
  if (timer == NULL)
    return NULL;
  timer->interval = -1;
  timer->handler = NULL;
  timer->multihandler = NULL;
  timer->userdata = NULL;
  timer->next = NULL;
  timer->previous = NULL;
  timer->group = timer;
  tl_reset_timer (timer);
  return (timer);
}


void
tl_free_timer (tl_timer * timer)
{
  if (timer->group)
    tl_remove_timer (timer);
  free ((void *) timer);
}

void
tl_free_group (tl_group * timer)
{
  tl_timer *next;
  do
    {
      next = timer->next;
      free ((void *) timer);
    }
  while (next != NULL);
}
int
tl_process_group (tl_group * group, int *activated)
{
  int again = 1;
  tl_timer *timer, *timer1;
  int minwait = INT_MAX;
  tl_update_time ();
  if (activated != NULL)
    *activated = 0;
  while (again)
    {
      group->slowdown=0;
      again = 0;
      minwait = INT_MAX;
      timer = group->next;
      while (timer != NULL)
      {
        timer1 = timer->next;
        if (timer->handler && timer->interval >= 0)
          {
            int time = timer->interval - tl_lookup_timer (timer);
            if (time <= 0)
            {
              if (activated != NULL)
                (*activated)++;
              again = 1;
              tl_reset_timer (timer);
              if (time < -200 * 1000000)
                time = 0;     /*underflow? */
              tl_slowdown_timer (timer, time);
              time = timer->interval + time;
              timer->handler (timer->userdata);
              tl_update_time ();
            }
            if (time < minwait)
            minwait = time;
          }
        else if (timer->multihandler && timer->interval > 0)
          {
            int time = timer->interval - tl_lookup_timer (timer);
            if (time <= 0)
            {
              int n;
              if (activated != NULL)
                (*activated)++;
              tl_reset_timer (timer);
              if (time < -200 * 1000000)
                time = 0;     /*underflow? */
              n = -(time) / timer->interval + 1;
              time += timer->interval * n;
              tl_slowdown_timer (timer, time - timer->interval);
              timer->multihandler (timer->userdata, n);
              tl_update_time ();
            }
            if (time < minwait)
            minwait = time;
          }
        if(group->slowdown) {again=1;break;}
        timer = timer1;
      }
    }
  if (minwait != INT_MAX)
    {
      if (minwait < 0)
      return (0);
      return (minwait + 500);
    }
  return (-1);
}
#ifdef HAVE_SETITIMER
static void update_async (void);
static void
alarmhandler (int a)
{
  update_async ();
  signal (SIGALRM, alarmhandler);
}
static void
update_async (void)
{
  int time = tl_process_group (asyncgroup, NULL);
  if (time != -1)
    {
      struct itimerval t;
      t.it_interval.tv_sec = 0;
      t.it_interval.tv_usec = 0;
      t.it_value.tv_sec = time / 1000000;
      t.it_value.tv_usec = time % 1000000;
      if (!reghandler)
      {
        signal (SIGALRM, alarmhandler), reghandler = 1;
      }
      setitimer (ITIMER_REAL, &t, &t);
      registered = 1;
    }
  else if (registered)
    {
      struct itimerval t;
      t.it_interval.tv_sec = 0;
      t.it_interval.tv_usec = 0;
      t.it_value.tv_sec = 0;
      t.it_value.tv_usec = 0;
      setitimer (ITIMER_REAL, &t, &t);
      registered = 0;
    }
}

#else
#define update_async()
#endif
void
tl_add_timer (tl_group * group, tl_timer * timer)
{
  if (timer->group) tl_remove_timer (timer);
  timer->previous = group;
  timer->next = group->next;
  timer->group = group;
  group->next = timer;
  if(timer->next!=NULL) timer->next->previous=timer;
  if (timer->group == asyncgroup)
    update_async ();
}
void
tl_set_interval (tl_timer * timer, int interval)
{
  if (timer->interval <= 0)
    {
      tl_reset_timer (timer);
    }
  timer->interval = interval;
  if (timer->group == asyncgroup)
    update_async ();
}

void
tl_set_handler (tl_timer * timer, void (*handler) (void *), void *ud)
{
  timer->handler = handler;
  timer->userdata = ud;
  if (timer->group == asyncgroup)
    update_async ();
}
void
tl_set_multihandler (tl_timer * timer, void (*handler) (void *, int), void *ud)
{
  timer->multihandler = handler;
  timer->userdata = ud;
  if (timer->group == asyncgroup)
    update_async ();
}

void
tl_remove_timer (tl_timer * timer)
{
  tl_group *g = timer->group;
  timer->group->slowdown=1;
  timer->previous->next = timer->next;
  if (timer->next != NULL)
    timer->next->previous = timer->previous;
  timer->group = NULL;
  if (g == asyncgroup)
    update_async ();
}

struct timeemulator *tl_create_emulator(void)
{
  return((struct timeemulator *)calloc(1,sizeof(struct timeemulator)));
}
void tl_free_emulator(struct timeemulator *t)
{
  free(t);
}
void tl_elpased(struct timeemulator *t, int elpased)
{
  t->exact+=elpased;
  t->time+=t->exact/EMULDIV;
  t->exact&=(EMULDIV-1);
}
void tl_emulate_timer(struct timer *t, struct timeemulator *e)
{
  int time=tl_lookup_timer(t);
  t->emulator=e;
  t->lastemulated=e->time;
  tl_slowdown_timer(t,-time);
}
void tl_unemulate_timer(struct timer *t)
{
  int time=tl_lookup_timer(t);
  t->emulator=NULL;
  tl_slowdown_timer(t,tl_lookup_timer(t)-time);
}
#ifdef USE_ALLEGRO
void
tl_allegromode (int mode)
{
  allegromode = mode;
  if (!allegromode && ainstalled)
    {
      remove_int (timer);
      ainstalled = 0;
      counter = -1;
    }
}
#endif

Generated by  Doxygen 1.6.0   Back to index