Diff for /qemu/qemu-timer.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2018/04/24 18:33:57 version 1.1.1.3, 2018/04/24 18:56:13
Line 39 Line 39
 #include <sys/param.h>  #include <sys/param.h>
 #endif  #endif
   
 #ifdef __linux__  
 #include <sys/ioctl.h>  
 #include <linux/rtc.h>  
 /* For the benefit of older linux systems which don't supply it,  
    we use a local copy of hpet.h. */  
 /* #include <linux/hpet.h> */  
 #include "hpet.h"  
 #endif  
   
 #ifdef _WIN32  #ifdef _WIN32
 #include <windows.h>  #include <windows.h>
 #include <mmsystem.h>  #include <mmsystem.h>
Line 110  static int64_t cpu_get_clock(void) Line 101  static int64_t cpu_get_clock(void)
     }      }
 }  }
   
   #ifndef CONFIG_IOTHREAD
 static int64_t qemu_icount_delta(void)  static int64_t qemu_icount_delta(void)
 {  {
     if (!use_icount) {      if (!use_icount) {
Line 123  static int64_t qemu_icount_delta(void) Line 115  static int64_t qemu_icount_delta(void)
         return cpu_get_icount() - cpu_get_clock();          return cpu_get_icount() - cpu_get_clock();
     }      }
 }  }
   #endif
   
 /* enable cpu_get_ticks() */  /* enable cpu_get_ticks() */
 void cpu_enable_ticks(void)  void cpu_enable_ticks(void)
Line 155  void cpu_disable_ticks(void) Line 148  void cpu_disable_ticks(void)
 struct QEMUClock {  struct QEMUClock {
     int type;      int type;
     int enabled;      int enabled;
     /* XXX: add frequency */  
       QEMUTimer *warp_timer;
   
       NotifierList reset_notifiers;
       int64_t last;
 };  };
   
 struct QEMUTimer {  struct QEMUTimer {
     QEMUClock *clock;      QEMUClock *clock;
     int64_t expire_time;      int64_t expire_time;        /* in nanoseconds */
       int scale;
     QEMUTimerCB *cb;      QEMUTimerCB *cb;
     void *opaque;      void *opaque;
     struct QEMUTimer *next;      struct QEMUTimer *next;
Line 171  struct qemu_alarm_timer { Line 169  struct qemu_alarm_timer {
     int (*start)(struct qemu_alarm_timer *t);      int (*start)(struct qemu_alarm_timer *t);
     void (*stop)(struct qemu_alarm_timer *t);      void (*stop)(struct qemu_alarm_timer *t);
     void (*rearm)(struct qemu_alarm_timer *t);      void (*rearm)(struct qemu_alarm_timer *t);
     void *priv;  #if defined(__linux__)
       int fd;
       timer_t timer;
   #elif defined(_WIN32)
       HANDLE timer;
   #endif
     char expired;      char expired;
     char pending;      char pending;
 };  };
   
 static struct qemu_alarm_timer *alarm_timer;  static struct qemu_alarm_timer *alarm_timer;
   
   static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
   {
       return timer_head && (timer_head->expire_time <= current_time);
   }
   
 int qemu_alarm_pending(void)  int qemu_alarm_pending(void)
 {  {
     return alarm_timer->pending;      return alarm_timer->pending;
Line 202  static void qemu_rearm_alarm_timer(struc Line 209  static void qemu_rearm_alarm_timer(struc
   
 #ifdef _WIN32  #ifdef _WIN32
   
 struct qemu_alarm_win32 {  static int mm_start_timer(struct qemu_alarm_timer *t);
     MMRESULT timerId;  static void mm_stop_timer(struct qemu_alarm_timer *t);
     unsigned int period;  static void mm_rearm_timer(struct qemu_alarm_timer *t);
 } alarm_win32_data = {0, 0};  
   
 static int win32_start_timer(struct qemu_alarm_timer *t);  static int win32_start_timer(struct qemu_alarm_timer *t);
 static void win32_stop_timer(struct qemu_alarm_timer *t);  static void win32_stop_timer(struct qemu_alarm_timer *t);
Line 215  static void win32_rearm_timer(struct qem Line 221  static void win32_rearm_timer(struct qem
   
 static int unix_start_timer(struct qemu_alarm_timer *t);  static int unix_start_timer(struct qemu_alarm_timer *t);
 static void unix_stop_timer(struct qemu_alarm_timer *t);  static void unix_stop_timer(struct qemu_alarm_timer *t);
   static void unix_rearm_timer(struct qemu_alarm_timer *t);
   
 #ifdef __linux__  #ifdef __linux__
   
Line 222  static int dynticks_start_timer(struct q Line 229  static int dynticks_start_timer(struct q
 static void dynticks_stop_timer(struct qemu_alarm_timer *t);  static void dynticks_stop_timer(struct qemu_alarm_timer *t);
 static void dynticks_rearm_timer(struct qemu_alarm_timer *t);  static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
   
 static int hpet_start_timer(struct qemu_alarm_timer *t);  
 static void hpet_stop_timer(struct qemu_alarm_timer *t);  
   
 static int rtc_start_timer(struct qemu_alarm_timer *t);  
 static void rtc_stop_timer(struct qemu_alarm_timer *t);  
   
 #endif /* __linux__ */  #endif /* __linux__ */
   
 #endif /* _WIN32 */  #endif /* _WIN32 */
Line 249  static void icount_adjust(void) Line 250  static void icount_adjust(void)
         return;          return;
   
     cur_time = cpu_get_clock();      cur_time = cpu_get_clock();
     cur_icount = qemu_get_clock(vm_clock);      cur_icount = qemu_get_clock_ns(vm_clock);
     delta = cur_icount - cur_time;      delta = cur_icount - cur_time;
     /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */      /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
     if (delta > 0      if (delta > 0
Line 271  static void icount_adjust(void) Line 272  static void icount_adjust(void)
 static void icount_adjust_rt(void * opaque)  static void icount_adjust_rt(void * opaque)
 {  {
     qemu_mod_timer(icount_rt_timer,      qemu_mod_timer(icount_rt_timer,
                    qemu_get_clock(rt_clock) + 1000);                     qemu_get_clock_ms(rt_clock) + 1000);
     icount_adjust();      icount_adjust();
 }  }
   
 static void icount_adjust_vm(void * opaque)  static void icount_adjust_vm(void * opaque)
 {  {
     qemu_mod_timer(icount_vm_timer,      qemu_mod_timer(icount_vm_timer,
                    qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10);                     qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
     icount_adjust();      icount_adjust();
 }  }
   
Line 291  static struct qemu_alarm_timer alarm_tim Line 292  static struct qemu_alarm_timer alarm_tim
 #ifndef _WIN32  #ifndef _WIN32
 #ifdef __linux__  #ifdef __linux__
     {"dynticks", dynticks_start_timer,      {"dynticks", dynticks_start_timer,
      dynticks_stop_timer, dynticks_rearm_timer, NULL},       dynticks_stop_timer, dynticks_rearm_timer},
     /* HPET - if available - is preferred */  
     {"hpet", hpet_start_timer, hpet_stop_timer, NULL, NULL},  
     /* ...otherwise try RTC */  
     {"rtc", rtc_start_timer, rtc_stop_timer, NULL, NULL},  
 #endif  #endif
     {"unix", unix_start_timer, unix_stop_timer, NULL, NULL},      {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer},
 #else  #else
     {"dynticks", win32_start_timer,      {"mmtimer", mm_start_timer, mm_stop_timer, NULL},
      win32_stop_timer, win32_rearm_timer, &alarm_win32_data},      {"mmtimer2", mm_start_timer, mm_stop_timer, mm_rearm_timer},
     {"win32", win32_start_timer,      {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer},
      win32_stop_timer, NULL, &alarm_win32_data},      {"win32", win32_start_timer, win32_stop_timer, NULL},
 #endif  #endif
     {NULL, }      {NULL, }
 };  };
Line 382  static QEMUTimer *active_timers[QEMU_NUM Line 379  static QEMUTimer *active_timers[QEMU_NUM
 static QEMUClock *qemu_new_clock(int type)  static QEMUClock *qemu_new_clock(int type)
 {  {
     QEMUClock *clock;      QEMUClock *clock;
   
     clock = qemu_mallocz(sizeof(QEMUClock));      clock = qemu_mallocz(sizeof(QEMUClock));
     clock->type = type;      clock->type = type;
     clock->enabled = 1;      clock->enabled = 1;
       notifier_list_init(&clock->reset_notifiers);
       /* required to detect & report backward jumps */
       if (type == QEMU_CLOCK_HOST) {
           clock->last = get_clock_realtime();
       }
     return clock;      return clock;
 }  }
   
Line 393  void qemu_clock_enable(QEMUClock *clock, Line 396  void qemu_clock_enable(QEMUClock *clock,
     clock->enabled = enabled;      clock->enabled = enabled;
 }  }
   
 QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)  static int64_t vm_clock_warp_start;
   
   static void icount_warp_rt(void *opaque)
   {
       if (vm_clock_warp_start == -1) {
           return;
       }
   
       if (vm_running) {
           int64_t clock = qemu_get_clock_ns(rt_clock);
           int64_t warp_delta = clock - vm_clock_warp_start;
           if (use_icount == 1) {
               qemu_icount_bias += warp_delta;
           } else {
               /*
                * In adaptive mode, do not let the vm_clock run too
                * far ahead of real time.
                */
               int64_t cur_time = cpu_get_clock();
               int64_t cur_icount = qemu_get_clock_ns(vm_clock);
               int64_t delta = cur_time - cur_icount;
               qemu_icount_bias += MIN(warp_delta, delta);
           }
           if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
                                  qemu_get_clock_ns(vm_clock))) {
               qemu_notify_event();
           }
       }
       vm_clock_warp_start = -1;
   }
   
   void qemu_clock_warp(QEMUClock *clock)
   {
       int64_t deadline;
   
       if (!clock->warp_timer) {
           return;
       }
   
       /*
        * There are too many global variables to make the "warp" behavior
        * applicable to other clocks.  But a clock argument removes the
        * need for if statements all over the place.
        */
       assert(clock == vm_clock);
   
       /*
        * If the CPUs have been sleeping, advance the vm_clock timer now.  This
        * ensures that the deadline for the timer is computed correctly below.
        * This also makes sure that the insn counter is synchronized before the
        * CPU starts running, in case the CPU is woken by an event other than
        * the earliest vm_clock timer.
        */
       icount_warp_rt(NULL);
       if (!all_cpu_threads_idle() || !active_timers[clock->type]) {
           qemu_del_timer(clock->warp_timer);
           return;
       }
   
       vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
       deadline = qemu_next_icount_deadline();
       if (deadline > 0) {
           /*
            * Ensure the vm_clock proceeds even when the virtual CPU goes to
            * sleep.  Otherwise, the CPU might be waiting for a future timer
            * interrupt to wake it up, but the interrupt never comes because
            * the vCPU isn't running any insns and thus doesn't advance the
            * vm_clock.
            *
            * An extreme solution for this problem would be to never let VCPUs
            * sleep in icount mode if there is a pending vm_clock timer; rather
            * time could just advance to the next vm_clock event.  Instead, we
            * do stop VCPUs and only advance vm_clock after some "real" time,
            * (related to the time left until the next event) has passed.  This
            * rt_clock timer will do this.  This avoids that the warps are too
            * visible externally---for example, you will not be sending network
            * packets continously instead of every 100ms.
            */
           qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline);
       } else {
           qemu_notify_event();
       }
   }
   
   QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
                             QEMUTimerCB *cb, void *opaque)
 {  {
     QEMUTimer *ts;      QEMUTimer *ts;
   
Line 401  QEMUTimer *qemu_new_timer(QEMUClock *clo Line 489  QEMUTimer *qemu_new_timer(QEMUClock *clo
     ts->clock = clock;      ts->clock = clock;
     ts->cb = cb;      ts->cb = cb;
     ts->opaque = opaque;      ts->opaque = opaque;
       ts->scale = scale;
     return ts;      return ts;
 }  }
   
Line 431  void qemu_del_timer(QEMUTimer *ts) Line 520  void qemu_del_timer(QEMUTimer *ts)
   
 /* modify the current timer so that it will be fired when current_time  /* modify the current timer so that it will be fired when current_time
    >= expire_time. The corresponding callback will be called. */     >= expire_time. The corresponding callback will be called. */
 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)  static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
 {  {
     QEMUTimer **pt, *t;      QEMUTimer **pt, *t;
   
Line 443  void qemu_mod_timer(QEMUTimer *ts, int64 Line 532  void qemu_mod_timer(QEMUTimer *ts, int64
     pt = &active_timers[ts->clock->type];      pt = &active_timers[ts->clock->type];
     for(;;) {      for(;;) {
         t = *pt;          t = *pt;
         if (!t)          if (!qemu_timer_expired_ns(t, expire_time)) {
             break;  
         if (t->expire_time > expire_time)  
             break;              break;
           }
         pt = &t->next;          pt = &t->next;
     }      }
     ts->expire_time = expire_time;      ts->expire_time = expire_time;
Line 459  void qemu_mod_timer(QEMUTimer *ts, int64 Line 547  void qemu_mod_timer(QEMUTimer *ts, int64
             qemu_rearm_alarm_timer(alarm_timer);              qemu_rearm_alarm_timer(alarm_timer);
         }          }
         /* Interrupt execution to force deadline recalculation.  */          /* Interrupt execution to force deadline recalculation.  */
         if (use_icount)          qemu_clock_warp(ts->clock);
           if (use_icount) {
             qemu_notify_event();              qemu_notify_event();
           }
     }      }
 }  }
   
   /* modify the current timer so that it will be fired when current_time
      >= expire_time. The corresponding callback will be called. */
   void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
   {
       qemu_mod_timer_ns(ts, expire_time * ts->scale);
   }
   
 int qemu_timer_pending(QEMUTimer *ts)  int qemu_timer_pending(QEMUTimer *ts)
 {  {
     QEMUTimer *t;      QEMUTimer *t;
Line 476  int qemu_timer_pending(QEMUTimer *ts) Line 573  int qemu_timer_pending(QEMUTimer *ts)
   
 int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)  int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
 {  {
     if (!timer_head)      return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
         return 0;  
     return (timer_head->expire_time <= current_time);  
 }  }
   
 static void qemu_run_timers(QEMUClock *clock)  static void qemu_run_timers(QEMUClock *clock)
Line 489  static void qemu_run_timers(QEMUClock *c Line 584  static void qemu_run_timers(QEMUClock *c
     if (!clock->enabled)      if (!clock->enabled)
         return;          return;
   
     current_time = qemu_get_clock (clock);      current_time = qemu_get_clock_ns(clock);
     ptimer_head = &active_timers[clock->type];      ptimer_head = &active_timers[clock->type];
     for(;;) {      for(;;) {
         ts = *ptimer_head;          ts = *ptimer_head;
         if (!ts || ts->expire_time > current_time)          if (!qemu_timer_expired_ns(ts, current_time)) {
             break;              break;
           }
         /* remove timer from the list before calling the callback */          /* remove timer from the list before calling the callback */
         *ptimer_head = ts->next;          *ptimer_head = ts->next;
         ts->next = NULL;          ts->next = NULL;
Line 504  static void qemu_run_timers(QEMUClock *c Line 600  static void qemu_run_timers(QEMUClock *c
     }      }
 }  }
   
 int64_t qemu_get_clock(QEMUClock *clock)  int64_t qemu_get_clock_ns(QEMUClock *clock)
 {  {
       int64_t now, last;
   
     switch(clock->type) {      switch(clock->type) {
     case QEMU_CLOCK_REALTIME:      case QEMU_CLOCK_REALTIME:
         return get_clock() / 1000000;          return get_clock();
     default:      default:
     case QEMU_CLOCK_VIRTUAL:      case QEMU_CLOCK_VIRTUAL:
         if (use_icount) {          if (use_icount) {
Line 517  int64_t qemu_get_clock(QEMUClock *clock) Line 615  int64_t qemu_get_clock(QEMUClock *clock)
             return cpu_get_clock();              return cpu_get_clock();
         }          }
     case QEMU_CLOCK_HOST:      case QEMU_CLOCK_HOST:
         return get_clock_realtime();          now = get_clock_realtime();
           last = clock->last;
           clock->last = now;
           if (now < last) {
               notifier_list_notify(&clock->reset_notifiers, &now);
           }
           return now;
     }      }
 }  }
   
 int64_t qemu_get_clock_ns(QEMUClock *clock)  void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
 {  {
     switch(clock->type) {      notifier_list_add(&clock->reset_notifiers, notifier);
     case QEMU_CLOCK_REALTIME:  }
         return get_clock();  
     default:  void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
     case QEMU_CLOCK_VIRTUAL:  {
         if (use_icount) {      notifier_list_remove(&clock->reset_notifiers, notifier);
             return cpu_get_icount();  
         } else {  
             return cpu_get_clock();  
         }  
     case QEMU_CLOCK_HOST:  
         return get_clock_realtime();  
     }  
 }  }
   
 void init_clocks(void)  void init_clocks(void)
Line 566  void qemu_get_timer(QEMUFile *f, QEMUTim Line 663  void qemu_get_timer(QEMUFile *f, QEMUTim
   
     expire_time = qemu_get_be64(f);      expire_time = qemu_get_be64(f);
     if (expire_time != -1) {      if (expire_time != -1) {
         qemu_mod_timer(ts, expire_time);          qemu_mod_timer_ns(ts, expire_time);
     } else {      } else {
         qemu_del_timer(ts);          qemu_del_timer(ts);
     }      }
Line 591  void configure_icount(const char *option Line 688  void configure_icount(const char *option
     if (!option)      if (!option)
         return;          return;
   
   #ifdef CONFIG_IOTHREAD
       vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
   #endif
   
     if (strcmp(option, "auto") != 0) {      if (strcmp(option, "auto") != 0) {
         icount_time_shift = strtol(option, NULL, 0);          icount_time_shift = strtol(option, NULL, 0);
         use_icount = 1;          use_icount = 1;
Line 608  void configure_icount(const char *option Line 709  void configure_icount(const char *option
        the virtual time trigger catches emulated time passing too fast.         the virtual time trigger catches emulated time passing too fast.
        Realtime triggers occur even when idle, so use them less frequently         Realtime triggers occur even when idle, so use them less frequently
        than VM triggers.  */         than VM triggers.  */
     icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL);      icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
     qemu_mod_timer(icount_rt_timer,      qemu_mod_timer(icount_rt_timer,
                    qemu_get_clock(rt_clock) + 1000);                     qemu_get_clock_ms(rt_clock) + 1000);
     icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);      icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
     qemu_mod_timer(icount_vm_timer,      qemu_mod_timer(icount_vm_timer,
                    qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10);                     qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
 }  }
   
 void qemu_run_all_timers(void)  void qemu_run_all_timers(void)
Line 638  void qemu_run_all_timers(void) Line 739  void qemu_run_all_timers(void)
 static int64_t qemu_next_alarm_deadline(void);  static int64_t qemu_next_alarm_deadline(void);
   
 #ifdef _WIN32  #ifdef _WIN32
 static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,  static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused)
                                         DWORD_PTR dwUser, DWORD_PTR dw1,  
                                         DWORD_PTR dw2)  
 #else  #else
 static void host_alarm_handler(int host_signum)  static void host_alarm_handler(int host_signum)
 #endif  #endif
Line 655  static void host_alarm_handler(int host_ Line 754  static void host_alarm_handler(int host_
         static int64_t delta_min = INT64_MAX;          static int64_t delta_min = INT64_MAX;
         static int64_t delta_max, delta_cum, last_clock, delta, ti;          static int64_t delta_max, delta_cum, last_clock, delta, ti;
         static int count;          static int count;
         ti = qemu_get_clock(vm_clock);          ti = qemu_get_clock_ns(vm_clock);
         if (last_clock != 0) {          if (last_clock != 0) {
             delta = ti - last_clock;              delta = ti - last_clock;
             if (delta < delta_min)              if (delta < delta_min)
Line 686  static void host_alarm_handler(int host_ Line 785  static void host_alarm_handler(int host_
     }      }
 }  }
   
 int64_t qemu_next_deadline(void)  int64_t qemu_next_icount_deadline(void)
 {  {
     /* To avoid problems with overflow limit this to 2^32.  */      /* To avoid problems with overflow limit this to 2^32.  */
     int64_t delta = INT32_MAX;      int64_t delta = INT32_MAX;
   
       assert(use_icount);
     if (active_timers[QEMU_CLOCK_VIRTUAL]) {      if (active_timers[QEMU_CLOCK_VIRTUAL]) {
         delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -          delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
                      qemu_get_clock_ns(vm_clock);                       qemu_get_clock_ns(vm_clock);
     }      }
     if (active_timers[QEMU_CLOCK_HOST]) {  
         int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -  
                  qemu_get_clock_ns(host_clock);  
         if (hdelta < delta)  
             delta = hdelta;  
     }  
   
     if (delta < 0)      if (delta < 0)
         delta = 0;          delta = 0;
Line 715  static int64_t qemu_next_alarm_deadline( Line 809  static int64_t qemu_next_alarm_deadline(
   
     if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {      if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
         delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -          delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
                      qemu_get_clock(vm_clock);                       qemu_get_clock_ns(vm_clock);
     } else {      } else {
         delta = INT32_MAX;          delta = INT32_MAX;
     }      }
Line 726  static int64_t qemu_next_alarm_deadline( Line 820  static int64_t qemu_next_alarm_deadline(
             delta = hdelta;              delta = hdelta;
     }      }
     if (active_timers[QEMU_CLOCK_REALTIME]) {      if (active_timers[QEMU_CLOCK_REALTIME]) {
         rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time * 1000000 -          rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
                  qemu_get_clock_ns(rt_clock));                   qemu_get_clock_ns(rt_clock));
         if (rtdelta < delta)          if (rtdelta < delta)
             delta = rtdelta;              delta = rtdelta;
Line 737  static int64_t qemu_next_alarm_deadline( Line 831  static int64_t qemu_next_alarm_deadline(
   
 #if defined(__linux__)  #if defined(__linux__)
   
 #define RTC_FREQ 1024  #include "compatfd.h"
   
 static void enable_sigio_timer(int fd)  
 {  
     struct sigaction act;  
   
     /* timer signal */  
     sigfillset(&act.sa_mask);  
     act.sa_flags = 0;  
     act.sa_handler = host_alarm_handler;  
   
     sigaction(SIGIO, &act, NULL);  
     fcntl_setfl(fd, O_ASYNC);  
     fcntl(fd, F_SETOWN, getpid());  
 }  
   
 static int hpet_start_timer(struct qemu_alarm_timer *t)  
 {  
     struct hpet_info info;  
     int r, fd;  
   
     fd = qemu_open("/dev/hpet", O_RDONLY);  
     if (fd < 0)  
         return -1;  
   
     /* Set frequency */  
     r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);  
     if (r < 0) {  
         fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"  
                 "error, but for better emulation accuracy type:\n"  
                 "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");  
         goto fail;  
     }  
   
     /* Check capabilities */  
     r = ioctl(fd, HPET_INFO, &info);  
     if (r < 0)  
         goto fail;  
   
     /* Enable periodic mode */  
     r = ioctl(fd, HPET_EPI, 0);  
     if (info.hi_flags && (r < 0))  
         goto fail;  
   
     /* Enable interrupt */  
     r = ioctl(fd, HPET_IE_ON, 0);  
     if (r < 0)  
         goto fail;  
   
     enable_sigio_timer(fd);  
     t->priv = (void *)(long)fd;  
   
     return 0;  
 fail:  
     close(fd);  
     return -1;  
 }  
   
 static void hpet_stop_timer(struct qemu_alarm_timer *t)  
 {  
     int fd = (long)t->priv;  
   
     close(fd);  
 }  
   
 static int rtc_start_timer(struct qemu_alarm_timer *t)  
 {  
     int rtc_fd;  
     unsigned long current_rtc_freq = 0;  
   
     TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY));  
     if (rtc_fd < 0)  
         return -1;  
     ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);  
     if (current_rtc_freq != RTC_FREQ &&  
         ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {  
         fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"  
                 "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"  
                 "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");  
         goto fail;  
     }  
     if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {  
     fail:  
         close(rtc_fd);  
         return -1;  
     }  
   
     enable_sigio_timer(rtc_fd);  
   
     t->priv = (void *)(long)rtc_fd;  
   
     return 0;  
 }  
   
 static void rtc_stop_timer(struct qemu_alarm_timer *t)  
 {  
     int rtc_fd = (long)t->priv;  
   
     close(rtc_fd);  
 }  
   
 static int dynticks_start_timer(struct qemu_alarm_timer *t)  static int dynticks_start_timer(struct qemu_alarm_timer *t)
 {  {
Line 857  static int dynticks_start_timer(struct q Line 852  static int dynticks_start_timer(struct q
     memset(&ev, 0, sizeof(ev));      memset(&ev, 0, sizeof(ev));
     ev.sigev_value.sival_int = 0;      ev.sigev_value.sival_int = 0;
     ev.sigev_notify = SIGEV_SIGNAL;      ev.sigev_notify = SIGEV_SIGNAL;
   #ifdef SIGEV_THREAD_ID
       if (qemu_signalfd_available()) {
           ev.sigev_notify = SIGEV_THREAD_ID;
           ev._sigev_un._tid = qemu_get_thread_id();
       }
   #endif /* SIGEV_THREAD_ID */
     ev.sigev_signo = SIGALRM;      ev.sigev_signo = SIGALRM;
   
     if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {      if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
Line 868  static int dynticks_start_timer(struct q Line 869  static int dynticks_start_timer(struct q
         return -1;          return -1;
     }      }
   
     t->priv = (void *)(long)host_timer;      t->timer = host_timer;
   
     return 0;      return 0;
 }  }
   
 static void dynticks_stop_timer(struct qemu_alarm_timer *t)  static void dynticks_stop_timer(struct qemu_alarm_timer *t)
 {  {
     timer_t host_timer = (timer_t)(long)t->priv;      timer_t host_timer = t->timer;
   
     timer_delete(host_timer);      timer_delete(host_timer);
 }  }
   
 static void dynticks_rearm_timer(struct qemu_alarm_timer *t)  static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
 {  {
     timer_t host_timer = (timer_t)(long)t->priv;      timer_t host_timer = t->timer;
     struct itimerspec timeout;      struct itimerspec timeout;
     int64_t nearest_delta_ns = INT64_MAX;      int64_t nearest_delta_ns = INT64_MAX;
     int64_t current_ns;      int64_t current_ns;
Line 925  static void dynticks_rearm_timer(struct  Line 926  static void dynticks_rearm_timer(struct 
 static int unix_start_timer(struct qemu_alarm_timer *t)  static int unix_start_timer(struct qemu_alarm_timer *t)
 {  {
     struct sigaction act;      struct sigaction act;
     struct itimerval itv;  
     int err;  
   
     /* timer signal */      /* timer signal */
     sigfillset(&act.sa_mask);      sigfillset(&act.sa_mask);
Line 934  static int unix_start_timer(struct qemu_ Line 933  static int unix_start_timer(struct qemu_
     act.sa_handler = host_alarm_handler;      act.sa_handler = host_alarm_handler;
   
     sigaction(SIGALRM, &act, NULL);      sigaction(SIGALRM, &act, NULL);
       return 0;
   }
   
     itv.it_interval.tv_sec = 0;  static void unix_rearm_timer(struct qemu_alarm_timer *t)
     /* for i386 kernel 2.6 to get 1 ms */  {
     itv.it_interval.tv_usec = 999;      struct itimerval itv;
     itv.it_value.tv_sec = 0;      int64_t nearest_delta_ns = INT64_MAX;
     itv.it_value.tv_usec = 10 * 1000;      int err;
   
     err = setitimer(ITIMER_REAL, &itv, NULL);      assert(alarm_has_dynticks(t));
     if (err)      if (!active_timers[QEMU_CLOCK_REALTIME] &&
         return -1;          !active_timers[QEMU_CLOCK_VIRTUAL] &&
           !active_timers[QEMU_CLOCK_HOST])
           return;
   
     return 0;      nearest_delta_ns = qemu_next_alarm_deadline();
       if (nearest_delta_ns < MIN_TIMER_REARM_NS)
           nearest_delta_ns = MIN_TIMER_REARM_NS;
   
       itv.it_interval.tv_sec = 0;
       itv.it_interval.tv_usec = 0; /* 0 for one-shot timer */
       itv.it_value.tv_sec =  nearest_delta_ns / 1000000000;
       itv.it_value.tv_usec = (nearest_delta_ns % 1000000000) / 1000;
       err = setitimer(ITIMER_REAL, &itv, NULL);
       if (err) {
           perror("setitimer");
           fprintf(stderr, "Internal timer error: aborting\n");
           exit(1);
       }
 }  }
   
 static void unix_stop_timer(struct qemu_alarm_timer *t)  static void unix_stop_timer(struct qemu_alarm_timer *t)
Line 961  static void unix_stop_timer(struct qemu_ Line 977  static void unix_stop_timer(struct qemu_
   
 #ifdef _WIN32  #ifdef _WIN32
   
 static int win32_start_timer(struct qemu_alarm_timer *t)  static MMRESULT mm_timer;
   static unsigned mm_period;
   
   static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
                                         DWORD_PTR dwUser, DWORD_PTR dw1,
                                         DWORD_PTR dw2)
   {
       struct qemu_alarm_timer *t = alarm_timer;
       if (!t) {
           return;
       }
       if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) {
           t->expired = alarm_has_dynticks(t);
           t->pending = 1;
           qemu_notify_event();
       }
   }
   
   static int mm_start_timer(struct qemu_alarm_timer *t)
 {  {
     TIMECAPS tc;      TIMECAPS tc;
     struct qemu_alarm_win32 *data = t->priv;  
     UINT flags;      UINT flags;
   
     memset(&tc, 0, sizeof(tc));      memset(&tc, 0, sizeof(tc));
     timeGetDevCaps(&tc, sizeof(tc));      timeGetDevCaps(&tc, sizeof(tc));
   
     data->period = tc.wPeriodMin;      mm_period = tc.wPeriodMin;
     timeBeginPeriod(data->period);      timeBeginPeriod(mm_period);
   
     flags = TIME_CALLBACK_FUNCTION;      flags = TIME_CALLBACK_FUNCTION;
     if (alarm_has_dynticks(t))      if (alarm_has_dynticks(t)) {
         flags |= TIME_ONESHOT;          flags |= TIME_ONESHOT;
     else      } else {
         flags |= TIME_PERIODIC;          flags |= TIME_PERIODIC;
       }
   
     data->timerId = timeSetEvent(1,         // interval (ms)      mm_timer = timeSetEvent(1,                  /* interval (ms) */
                         data->period,       // resolution                              mm_period,          /* resolution */
                         host_alarm_handler, // function                              mm_alarm_handler,   /* function */
                         (DWORD)t,           // parameter                              (DWORD_PTR)t,       /* parameter */
                         flags);                              flags);
   
     if (!data->timerId) {      if (!mm_timer) {
         fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",          fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
                 GetLastError());                  GetLastError());
         timeEndPeriod(data->period);          timeEndPeriod(mm_period);
         return -1;          return -1;
     }      }
   
     return 0;      return 0;
 }  }
   
 static void win32_stop_timer(struct qemu_alarm_timer *t)  static void mm_stop_timer(struct qemu_alarm_timer *t)
 {  {
     struct qemu_alarm_win32 *data = t->priv;      timeKillEvent(mm_timer);
       timeEndPeriod(mm_period);
     timeKillEvent(data->timerId);  
     timeEndPeriod(data->period);  
 }  }
   
 static void win32_rearm_timer(struct qemu_alarm_timer *t)  static void mm_rearm_timer(struct qemu_alarm_timer *t)
 {  {
     struct qemu_alarm_win32 *data = t->priv;      int nearest_delta_ms;
   
     assert(alarm_has_dynticks(t));      assert(alarm_has_dynticks(t));
     if (!active_timers[QEMU_CLOCK_REALTIME] &&      if (!active_timers[QEMU_CLOCK_REALTIME] &&
         !active_timers[QEMU_CLOCK_VIRTUAL] &&          !active_timers[QEMU_CLOCK_VIRTUAL] &&
         !active_timers[QEMU_CLOCK_HOST])          !active_timers[QEMU_CLOCK_HOST]) {
         return;          return;
       }
   
     timeKillEvent(data->timerId);      timeKillEvent(mm_timer);
   
     data->timerId = timeSetEvent(1,      nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
                         data->period,      if (nearest_delta_ms < 1) {
                         host_alarm_handler,          nearest_delta_ms = 1;
                         (DWORD)t,      }
                         TIME_ONESHOT | TIME_CALLBACK_FUNCTION);      mm_timer = timeSetEvent(nearest_delta_ms,
                               mm_period,
                               mm_alarm_handler,
                               (DWORD_PTR)t,
                               TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
   
     if (!data->timerId) {      if (!mm_timer) {
         fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",          fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
                 GetLastError());                  GetLastError());
   
         timeEndPeriod(data->period);          timeEndPeriod(mm_period);
         exit(1);          exit(1);
     }      }
 }  }
   
   static int win32_start_timer(struct qemu_alarm_timer *t)
   {
       HANDLE hTimer;
       BOOLEAN success;
   
       /* If you call ChangeTimerQueueTimer on a one-shot timer (its period
          is zero) that has already expired, the timer is not updated.  Since
          creating a new timer is relatively expensive, set a bogus one-hour
          interval in the dynticks case.  */
       success = CreateTimerQueueTimer(&hTimer,
                             NULL,
                             host_alarm_handler,
                             t,
                             1,
                             alarm_has_dynticks(t) ? 3600000 : 1,
                             WT_EXECUTEINTIMERTHREAD);
   
       if (!success) {
           fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
                   GetLastError());
           return -1;
       }
   
       t->timer = hTimer;
       return 0;
   }
   
   static void win32_stop_timer(struct qemu_alarm_timer *t)
   {
       HANDLE hTimer = t->timer;
   
       if (hTimer) {
           DeleteTimerQueueTimer(NULL, hTimer, NULL);
       }
   }
   
   static void win32_rearm_timer(struct qemu_alarm_timer *t)
   {
       HANDLE hTimer = t->timer;
       int nearest_delta_ms;
       BOOLEAN success;
   
       assert(alarm_has_dynticks(t));
       if (!active_timers[QEMU_CLOCK_REALTIME] &&
           !active_timers[QEMU_CLOCK_VIRTUAL] &&
           !active_timers[QEMU_CLOCK_HOST])
           return;
   
       nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
       if (nearest_delta_ms < 1) {
           nearest_delta_ms = 1;
       }
       success = ChangeTimerQueueTimer(NULL,
                                       hTimer,
                                       nearest_delta_ms,
                                       3600000);
   
       if (!success) {
           fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n",
                   GetLastError());
           exit(-1);
       }
   
   }
   
 #endif /* _WIN32 */  #endif /* _WIN32 */
   
 static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason)  static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason)
Line 1076  void quit_timers(void) Line 1178  void quit_timers(void)
   
 int qemu_calculate_timeout(void)  int qemu_calculate_timeout(void)
 {  {
   #ifndef CONFIG_IOTHREAD
     int timeout;      int timeout;
   
 #ifdef CONFIG_IOTHREAD  
     /* When using icount, making forward progress with qemu_icount when the  
        guest CPU is idle is critical. We only use the static io-thread timeout  
        for non icount runs.  */  
     if (!use_icount) {  
         return 1000;  
     }  
 #endif  
   
     if (!vm_running)      if (!vm_running)
         timeout = 5000;          timeout = 5000;
     else {      else {
Line 1102  int qemu_calculate_timeout(void) Line 1196  int qemu_calculate_timeout(void)
         } else {          } else {
             /* Wait for either IO to occur or the next              /* Wait for either IO to occur or the next
                timer event.  */                 timer event.  */
             add = qemu_next_deadline();              add = qemu_next_icount_deadline();
             /* We advance the timer before checking for IO.              /* We advance the timer before checking for IO.
                Limit the amount we advance so that early IO                 Limit the amount we advance so that early IO
                activity won't get the guest too far ahead.  */                 activity won't get the guest too far ahead.  */
Line 1117  int qemu_calculate_timeout(void) Line 1211  int qemu_calculate_timeout(void)
     }      }
   
     return timeout;      return timeout;
   #else /* CONFIG_IOTHREAD */
       return 1000;
   #endif
 }  }
   

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


unix.superglobalmegacorp.com