Diff for /qemu/cpus.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2018/04/24 18:34:10 version 1.1.1.3, 2018/04/24 18:56:26
Line 30 Line 30
 #include "gdbstub.h"  #include "gdbstub.h"
 #include "dma.h"  #include "dma.h"
 #include "kvm.h"  #include "kvm.h"
 #include "exec-all.h"  
   
   #include "qemu-thread.h"
 #include "cpus.h"  #include "cpus.h"
   
   #ifndef _WIN32
 #include "compatfd.h"  #include "compatfd.h"
 #ifdef CONFIG_LINUX  
 #include <sys/prctl.h>  
 #endif  #endif
   
 #ifdef SIGRTMIN  #ifdef SIGRTMIN
Line 44 Line 44
 #define SIG_IPI SIGUSR1  #define SIG_IPI SIGUSR1
 #endif  #endif
   
   #ifdef CONFIG_LINUX
   
   #include <sys/prctl.h>
   
 #ifndef PR_MCE_KILL  #ifndef PR_MCE_KILL
 #define PR_MCE_KILL 33  #define PR_MCE_KILL 33
 #endif  #endif
   
   #ifndef PR_MCE_KILL_SET
   #define PR_MCE_KILL_SET 1
   #endif
   
   #ifndef PR_MCE_KILL_EARLY
   #define PR_MCE_KILL_EARLY 1
   #endif
   
   #endif /* CONFIG_LINUX */
   
 static CPUState *next_cpu;  static CPUState *next_cpu;
   
 /***********************************************************/  /***********************************************************/
Line 119  static void do_vm_stop(int reason) Line 133  static void do_vm_stop(int reason)
   
 static int cpu_can_run(CPUState *env)  static int cpu_can_run(CPUState *env)
 {  {
     if (env->stop)      if (env->stop) {
         return 0;          return 0;
     if (env->stopped || !vm_running)      }
       if (env->stopped || !vm_running) {
         return 0;          return 0;
       }
     return 1;      return 1;
 }  }
   
 static int cpu_has_work(CPUState *env)  static bool cpu_thread_is_idle(CPUState *env)
 {  {
     if (env->stop)      if (env->stop || env->queued_work_first) {
         return 1;          return false;
     if (env->queued_work_first)      }
         return 1;      if (env->stopped || !vm_running) {
     if (env->stopped || !vm_running)          return true;
         return 0;      }
     if (!env->halted)      if (!env->halted || qemu_cpu_has_work(env) ||
         return 1;          (kvm_enabled() && kvm_irqchip_in_kernel())) {
     if (qemu_cpu_has_work(env))          return false;
         return 1;      }
     return 0;      return true;
 }  }
   
 static int any_cpu_has_work(void)  bool all_cpu_threads_idle(void)
 {  {
     CPUState *env;      CPUState *env;
   
     for (env = first_cpu; env != NULL; env = env->next_cpu)      for (env = first_cpu; env != NULL; env = env->next_cpu) {
         if (cpu_has_work(env))          if (!cpu_thread_is_idle(env)) {
             return 1;              return false;
     return 0;          }
       }
       return true;
 }  }
   
 static void cpu_debug_handler(CPUState *env)  static void cpu_handle_guest_debug(CPUState *env)
 {  {
     gdb_set_stop_cpu(env);      gdb_set_stop_cpu(env);
     debug_requested = EXCP_DEBUG;      qemu_system_debug_request();
     vm_stop(EXCP_DEBUG);  #ifdef CONFIG_IOTHREAD
       env->stopped = 1;
   #endif
 }  }
   
   #ifdef CONFIG_IOTHREAD
   static void cpu_signal(int sig)
   {
       if (cpu_single_env) {
           cpu_exit(cpu_single_env);
       }
       exit_request = 1;
   }
   #endif
   
   #ifdef CONFIG_LINUX
   static void sigbus_reraise(void)
   {
       sigset_t set;
       struct sigaction action;
   
       memset(&action, 0, sizeof(action));
       action.sa_handler = SIG_DFL;
       if (!sigaction(SIGBUS, &action, NULL)) {
           raise(SIGBUS);
           sigemptyset(&set);
           sigaddset(&set, SIGBUS);
           sigprocmask(SIG_UNBLOCK, &set, NULL);
       }
       perror("Failed to re-raise SIGBUS!\n");
       abort();
   }
   
   static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
                              void *ctx)
   {
       if (kvm_on_sigbus(siginfo->ssi_code,
                         (void *)(intptr_t)siginfo->ssi_addr)) {
           sigbus_reraise();
       }
   }
   
   static void qemu_init_sigbus(void)
   {
       struct sigaction action;
   
       memset(&action, 0, sizeof(action));
       action.sa_flags = SA_SIGINFO;
       action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
       sigaction(SIGBUS, &action, NULL);
   
       prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
   }
   
   static void qemu_kvm_eat_signals(CPUState *env)
   {
       struct timespec ts = { 0, 0 };
       siginfo_t siginfo;
       sigset_t waitset;
       sigset_t chkset;
       int r;
   
       sigemptyset(&waitset);
       sigaddset(&waitset, SIG_IPI);
       sigaddset(&waitset, SIGBUS);
   
       do {
           r = sigtimedwait(&waitset, &siginfo, &ts);
           if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
               perror("sigtimedwait");
               exit(1);
           }
   
           switch (r) {
           case SIGBUS:
               if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
                   sigbus_reraise();
               }
               break;
           default:
               break;
           }
   
           r = sigpending(&chkset);
           if (r == -1) {
               perror("sigpending");
               exit(1);
           }
       } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
   
   #ifndef CONFIG_IOTHREAD
       if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) {
           qemu_notify_event();
       }
   #endif
   }
   
   #else /* !CONFIG_LINUX */
   
   static void qemu_init_sigbus(void)
   {
   }
   
   static void qemu_kvm_eat_signals(CPUState *env)
   {
   }
   #endif /* !CONFIG_LINUX */
   
 #ifndef _WIN32  #ifndef _WIN32
 static int io_thread_fd = -1;  static int io_thread_fd = -1;
   
Line 167  static void qemu_event_increment(void) Line 290  static void qemu_event_increment(void)
     static const uint64_t val = 1;      static const uint64_t val = 1;
     ssize_t ret;      ssize_t ret;
   
     if (io_thread_fd == -1)      if (io_thread_fd == -1) {
         return;          return;
       }
     do {      do {
         ret = write(io_thread_fd, &val, sizeof(val));          ret = write(io_thread_fd, &val, sizeof(val));
     } while (ret < 0 && errno == EINTR);      } while (ret < 0 && errno == EINTR);
   
     /* EAGAIN is fine, a read must be pending.  */      /* EAGAIN is fine, a read must be pending.  */
     if (ret < 0 && errno != EAGAIN) {      if (ret < 0 && errno != EAGAIN) {
         fprintf(stderr, "qemu_event_increment: write() filed: %s\n",          fprintf(stderr, "qemu_event_increment: write() failed: %s\n",
                 strerror(errno));                  strerror(errno));
         exit (1);          exit (1);
     }      }
Line 184  static void qemu_event_increment(void) Line 307  static void qemu_event_increment(void)
   
 static void qemu_event_read(void *opaque)  static void qemu_event_read(void *opaque)
 {  {
     int fd = (unsigned long)opaque;      int fd = (intptr_t)opaque;
     ssize_t len;      ssize_t len;
     char buffer[512];      char buffer[512];
   
Line 200  static int qemu_event_init(void) Line 323  static int qemu_event_init(void)
     int fds[2];      int fds[2];
   
     err = qemu_eventfd(fds);      err = qemu_eventfd(fds);
     if (err == -1)      if (err == -1) {
         return -errno;          return -errno;
       }
     err = fcntl_setfl(fds[0], O_NONBLOCK);      err = fcntl_setfl(fds[0], O_NONBLOCK);
     if (err < 0)      if (err < 0) {
         goto fail;          goto fail;
       }
     err = fcntl_setfl(fds[1], O_NONBLOCK);      err = fcntl_setfl(fds[1], O_NONBLOCK);
     if (err < 0)      if (err < 0) {
         goto fail;          goto fail;
       }
     qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,      qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
                          (void *)(unsigned long)fds[0]);                           (void *)(intptr_t)fds[0]);
   
     io_thread_fd = fds[1];      io_thread_fd = fds[1];
     return 0;      return 0;
Line 222  fail: Line 345  fail:
     close(fds[1]);      close(fds[1]);
     return err;      return err;
 }  }
   
   static void dummy_signal(int sig)
   {
   }
   
   /* If we have signalfd, we mask out the signals we want to handle and then
    * use signalfd to listen for them.  We rely on whatever the current signal
    * handler is to dispatch the signals when we receive them.
    */
   static void sigfd_handler(void *opaque)
   {
       int fd = (intptr_t)opaque;
       struct qemu_signalfd_siginfo info;
       struct sigaction action;
       ssize_t len;
   
       while (1) {
           do {
               len = read(fd, &info, sizeof(info));
           } while (len == -1 && errno == EINTR);
   
           if (len == -1 && errno == EAGAIN) {
               break;
           }
   
           if (len != sizeof(info)) {
               printf("read from sigfd returned %zd: %m\n", len);
               return;
           }
   
           sigaction(info.ssi_signo, NULL, &action);
           if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
               action.sa_sigaction(info.ssi_signo,
                                   (siginfo_t *)&info, NULL);
           } else if (action.sa_handler) {
               action.sa_handler(info.ssi_signo);
           }
       }
   }
   
   static int qemu_signal_init(void)
   {
       int sigfd;
       sigset_t set;
   
   #ifdef CONFIG_IOTHREAD
       /* SIGUSR2 used by posix-aio-compat.c */
       sigemptyset(&set);
       sigaddset(&set, SIGUSR2);
       pthread_sigmask(SIG_UNBLOCK, &set, NULL);
   
       /*
        * SIG_IPI must be blocked in the main thread and must not be caught
        * by sigwait() in the signal thread. Otherwise, the cpu thread will
        * not catch it reliably.
        */
       sigemptyset(&set);
       sigaddset(&set, SIG_IPI);
       pthread_sigmask(SIG_BLOCK, &set, NULL);
   
       sigemptyset(&set);
       sigaddset(&set, SIGIO);
       sigaddset(&set, SIGALRM);
       sigaddset(&set, SIGBUS);
 #else  #else
       sigemptyset(&set);
       sigaddset(&set, SIGBUS);
       if (kvm_enabled()) {
           /*
            * We need to process timer signals synchronously to avoid a race
            * between exit_request check and KVM vcpu entry.
            */
           sigaddset(&set, SIGIO);
           sigaddset(&set, SIGALRM);
       }
   #endif
       pthread_sigmask(SIG_BLOCK, &set, NULL);
   
       sigfd = qemu_signalfd(&set);
       if (sigfd == -1) {
           fprintf(stderr, "failed to create signalfd\n");
           return -errno;
       }
   
       fcntl_setfl(sigfd, O_NONBLOCK);
   
       qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
                            (void *)(intptr_t)sigfd);
   
       return 0;
   }
   
   static void qemu_kvm_init_cpu_signals(CPUState *env)
   {
       int r;
       sigset_t set;
       struct sigaction sigact;
   
       memset(&sigact, 0, sizeof(sigact));
       sigact.sa_handler = dummy_signal;
       sigaction(SIG_IPI, &sigact, NULL);
   
   #ifdef CONFIG_IOTHREAD
       pthread_sigmask(SIG_BLOCK, NULL, &set);
       sigdelset(&set, SIG_IPI);
       sigdelset(&set, SIGBUS);
       r = kvm_set_signal_mask(env, &set);
       if (r) {
           fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
           exit(1);
       }
   #else
       sigemptyset(&set);
       sigaddset(&set, SIG_IPI);
       sigaddset(&set, SIGIO);
       sigaddset(&set, SIGALRM);
       pthread_sigmask(SIG_BLOCK, &set, NULL);
   
       pthread_sigmask(SIG_BLOCK, NULL, &set);
       sigdelset(&set, SIGIO);
       sigdelset(&set, SIGALRM);
   #endif
       sigdelset(&set, SIG_IPI);
       sigdelset(&set, SIGBUS);
       r = kvm_set_signal_mask(env, &set);
       if (r) {
           fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
           exit(1);
       }
   }
   
   static void qemu_tcg_init_cpu_signals(void)
   {
   #ifdef CONFIG_IOTHREAD
       sigset_t set;
       struct sigaction sigact;
   
       memset(&sigact, 0, sizeof(sigact));
       sigact.sa_handler = cpu_signal;
       sigaction(SIG_IPI, &sigact, NULL);
   
       sigemptyset(&set);
       sigaddset(&set, SIG_IPI);
       pthread_sigmask(SIG_UNBLOCK, &set, NULL);
   #endif
   }
   
   #else /* _WIN32 */
   
 HANDLE qemu_event_handle;  HANDLE qemu_event_handle;
   
 static void dummy_event_handler(void *opaque)  static void dummy_event_handler(void *opaque)
Line 248  static void qemu_event_increment(void) Line 519  static void qemu_event_increment(void)
         exit (1);          exit (1);
     }      }
 }  }
 #endif  
   static int qemu_signal_init(void)
   {
       return 0;
   }
   
   static void qemu_kvm_init_cpu_signals(CPUState *env)
   {
       abort();
   }
   
   static void qemu_tcg_init_cpu_signals(void)
   {
   }
   #endif /* _WIN32 */
   
 #ifndef CONFIG_IOTHREAD  #ifndef CONFIG_IOTHREAD
 int qemu_init_main_loop(void)  int qemu_init_main_loop(void)
 {  {
     cpu_set_debug_excp_handler(cpu_debug_handler);      int ret;
   
       ret = qemu_signal_init();
       if (ret) {
           return ret;
       }
   
       qemu_init_sigbus();
   
     return qemu_event_init();      return qemu_event_init();
 }  }
Line 265  void qemu_main_loop_start(void) Line 557  void qemu_main_loop_start(void)
 void qemu_init_vcpu(void *_env)  void qemu_init_vcpu(void *_env)
 {  {
     CPUState *env = _env;      CPUState *env = _env;
       int r;
   
     env->nr_cores = smp_cores;      env->nr_cores = smp_cores;
     env->nr_threads = smp_threads;      env->nr_threads = smp_threads;
     if (kvm_enabled())  
         kvm_init_vcpu(env);      if (kvm_enabled()) {
     return;          r = kvm_init_vcpu(env);
           if (r < 0) {
               fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r));
               exit(1);
           }
           qemu_kvm_init_cpu_signals(env);
       } else {
           qemu_tcg_init_cpu_signals();
       }
 }  }
   
 int qemu_cpu_self(void *env)  int qemu_cpu_is_self(void *env)
 {  {
     return 1;      return 1;
 }  }
Line 293  void pause_all_vcpus(void) Line 594  void pause_all_vcpus(void)
   
 void qemu_cpu_kick(void *env)  void qemu_cpu_kick(void *env)
 {  {
     return;  }
   
   void qemu_cpu_kick_self(void)
   {
   #ifndef _WIN32
       assert(cpu_single_env);
   
       raise(SIG_IPI);
   #else
       abort();
   #endif
 }  }
   
 void qemu_notify_event(void)  void qemu_notify_event(void)
Line 307  void qemu_notify_event(void) Line 618  void qemu_notify_event(void)
     if (next_cpu && env != next_cpu) {      if (next_cpu && env != next_cpu) {
         cpu_exit(next_cpu);          cpu_exit(next_cpu);
     }      }
       exit_request = 1;
 }  }
   
 void qemu_mutex_lock_iothread(void) {}  void qemu_mutex_lock_iothread(void) {}
 void qemu_mutex_unlock_iothread(void) {}  void qemu_mutex_unlock_iothread(void) {}
   
   void cpu_stop_current(void)
   {
   }
   
 void vm_stop(int reason)  void vm_stop(int reason)
 {  {
     do_vm_stop(reason);      do_vm_stop(reason);
Line 319  void vm_stop(int reason) Line 635  void vm_stop(int reason)
   
 #else /* CONFIG_IOTHREAD */  #else /* CONFIG_IOTHREAD */
   
 #include "qemu-thread.h"  
   
 QemuMutex qemu_global_mutex;  QemuMutex qemu_global_mutex;
 static QemuMutex qemu_fair_mutex;  static QemuCond qemu_io_proceeded_cond;
   static bool iothread_requesting_mutex;
   
 static QemuThread io_thread;  static QemuThread io_thread;
   
Line 337  static QemuCond qemu_system_cond; Line 652  static QemuCond qemu_system_cond;
 static QemuCond qemu_pause_cond;  static QemuCond qemu_pause_cond;
 static QemuCond qemu_work_cond;  static QemuCond qemu_work_cond;
   
 static void tcg_init_ipi(void);  
 static void kvm_init_ipi(CPUState *env);  
 static sigset_t block_io_signals(void);  
   
 /* If we have signalfd, we mask out the signals we want to handle and then  
  * use signalfd to listen for them.  We rely on whatever the current signal  
  * handler is to dispatch the signals when we receive them.  
  */  
 static void sigfd_handler(void *opaque)  
 {  
     int fd = (unsigned long) opaque;  
     struct qemu_signalfd_siginfo info;  
     struct sigaction action;  
     ssize_t len;  
   
     while (1) {  
         do {  
             len = read(fd, &info, sizeof(info));  
         } while (len == -1 && errno == EINTR);  
   
         if (len == -1 && errno == EAGAIN) {  
             break;  
         }  
   
         if (len != sizeof(info)) {  
             printf("read from sigfd returned %zd: %m\n", len);  
             return;  
         }  
   
         sigaction(info.ssi_signo, NULL, &action);  
         if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {  
             action.sa_sigaction(info.ssi_signo,  
                                 (siginfo_t *)&info, NULL);  
         } else if (action.sa_handler) {  
             action.sa_handler(info.ssi_signo);  
         }  
     }  
 }  
   
 static int qemu_signalfd_init(sigset_t mask)  
 {  
     int sigfd;  
   
     sigfd = qemu_signalfd(&mask);  
     if (sigfd == -1) {  
         fprintf(stderr, "failed to create signalfd\n");  
         return -errno;  
     }  
   
     fcntl_setfl(sigfd, O_NONBLOCK);  
   
     qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,  
                          (void *)(unsigned long) sigfd);  
   
     return 0;  
 }  
   
 int qemu_init_main_loop(void)  int qemu_init_main_loop(void)
 {  {
     int ret;      int ret;
     sigset_t blocked_signals;  
   
     cpu_set_debug_excp_handler(cpu_debug_handler);  
   
     blocked_signals = block_io_signals();      qemu_init_sigbus();
   
     ret = qemu_signalfd_init(blocked_signals);      ret = qemu_signal_init();
     if (ret)      if (ret) {
         return ret;          return ret;
       }
   
     /* Note eventfd must be drained before signalfd handlers run */      /* Note eventfd must be drained before signalfd handlers run */
     ret = qemu_event_init();      ret = qemu_event_init();
     if (ret)      if (ret) {
         return ret;          return ret;
       }
   
     qemu_cond_init(&qemu_pause_cond);      qemu_cond_init(&qemu_cpu_cond);
     qemu_cond_init(&qemu_system_cond);      qemu_cond_init(&qemu_system_cond);
     qemu_mutex_init(&qemu_fair_mutex);      qemu_cond_init(&qemu_pause_cond);
       qemu_cond_init(&qemu_work_cond);
       qemu_cond_init(&qemu_io_proceeded_cond);
     qemu_mutex_init(&qemu_global_mutex);      qemu_mutex_init(&qemu_global_mutex);
     qemu_mutex_lock(&qemu_global_mutex);      qemu_mutex_lock(&qemu_global_mutex);
   
     qemu_thread_self(&io_thread);      qemu_thread_get_self(&io_thread);
   
     return 0;      return 0;
 }  }
Line 433  void run_on_cpu(CPUState *env, void (*fu Line 692  void run_on_cpu(CPUState *env, void (*fu
 {  {
     struct qemu_work_item wi;      struct qemu_work_item wi;
   
     if (qemu_cpu_self(env)) {      if (qemu_cpu_is_self(env)) {
         func(data);          func(data);
         return;          return;
     }      }
   
     wi.func = func;      wi.func = func;
     wi.data = data;      wi.data = data;
     if (!env->queued_work_first)      if (!env->queued_work_first) {
         env->queued_work_first = &wi;          env->queued_work_first = &wi;
     else      } else {
         env->queued_work_last->next = &wi;          env->queued_work_last->next = &wi;
       }
     env->queued_work_last = &wi;      env->queued_work_last = &wi;
     wi.next = NULL;      wi.next = NULL;
     wi.done = false;      wi.done = false;
Line 461  static void flush_queued_work(CPUState * Line 721  static void flush_queued_work(CPUState *
 {  {
     struct qemu_work_item *wi;      struct qemu_work_item *wi;
   
     if (!env->queued_work_first)      if (!env->queued_work_first) {
         return;          return;
       }
   
     while ((wi = env->queued_work_first)) {      while ((wi = env->queued_work_first)) {
         env->queued_work_first = wi->next;          env->queued_work_first = wi->next;
Line 481  static void qemu_wait_io_event_common(CP Line 742  static void qemu_wait_io_event_common(CP
         qemu_cond_signal(&qemu_pause_cond);          qemu_cond_signal(&qemu_pause_cond);
     }      }
     flush_queued_work(env);      flush_queued_work(env);
       env->thread_kicked = false;
 }  }
   
 static void qemu_tcg_wait_io_event(void)  static void qemu_tcg_wait_io_event(void)
 {  {
     CPUState *env;      CPUState *env;
   
     while (!any_cpu_has_work())      while (all_cpu_threads_idle()) {
         qemu_cond_timedwait(tcg_halt_cond, &qemu_global_mutex, 1000);         /* Start accounting real time to the virtual clock if the CPUs
             are idle.  */
     qemu_mutex_unlock(&qemu_global_mutex);          qemu_clock_warp(vm_clock);
           qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
     /*      }
      * Users of qemu_global_mutex can be starved, having no chance  
      * to acquire it since this path will get to it first.  
      * So use another lock to provide fairness.  
      */  
     qemu_mutex_lock(&qemu_fair_mutex);  
     qemu_mutex_unlock(&qemu_fair_mutex);  
   
     qemu_mutex_lock(&qemu_global_mutex);      while (iothread_requesting_mutex) {
           qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
       }
   
     for (env = first_cpu; env != NULL; env = env->next_cpu) {      for (env = first_cpu; env != NULL; env = env->next_cpu) {
         qemu_wait_io_event_common(env);          qemu_wait_io_event_common(env);
     }      }
 }  }
   
 static void sigbus_reraise(void)  
 {  
     sigset_t set;  
     struct sigaction action;  
   
     memset(&action, 0, sizeof(action));  
     action.sa_handler = SIG_DFL;  
     if (!sigaction(SIGBUS, &action, NULL)) {  
         raise(SIGBUS);  
         sigemptyset(&set);  
         sigaddset(&set, SIGBUS);  
         sigprocmask(SIG_UNBLOCK, &set, NULL);  
     }  
     perror("Failed to re-raise SIGBUS!\n");  
     abort();  
 }  
   
 static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,  
                            void *ctx)  
 {  
 #if defined(TARGET_I386)  
     if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr))  
 #endif  
         sigbus_reraise();  
 }  
   
 static void qemu_kvm_eat_signal(CPUState *env, int timeout)  
 {  
     struct timespec ts;  
     int r, e;  
     siginfo_t siginfo;  
     sigset_t waitset;  
     sigset_t chkset;  
   
     ts.tv_sec = timeout / 1000;  
     ts.tv_nsec = (timeout % 1000) * 1000000;  
   
     sigemptyset(&waitset);  
     sigaddset(&waitset, SIG_IPI);  
     sigaddset(&waitset, SIGBUS);  
   
     do {  
         qemu_mutex_unlock(&qemu_global_mutex);  
   
         r = sigtimedwait(&waitset, &siginfo, &ts);  
         e = errno;  
   
         qemu_mutex_lock(&qemu_global_mutex);  
   
         if (r == -1 && !(e == EAGAIN || e == EINTR)) {  
             fprintf(stderr, "sigtimedwait: %s\n", strerror(e));  
             exit(1);  
         }  
   
         switch (r) {  
         case SIGBUS:  
 #ifdef TARGET_I386  
             if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))  
 #endif  
                 sigbus_reraise();  
             break;  
         default:  
             break;  
         }  
   
         r = sigpending(&chkset);  
         if (r == -1) {  
             fprintf(stderr, "sigpending: %s\n", strerror(e));  
             exit(1);  
         }  
     } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));  
 }  
   
 static void qemu_kvm_wait_io_event(CPUState *env)  static void qemu_kvm_wait_io_event(CPUState *env)
 {  {
     while (!cpu_has_work(env))      while (cpu_thread_is_idle(env)) {
         qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);          qemu_cond_wait(env->halt_cond, &qemu_global_mutex);
       }
   
     qemu_kvm_eat_signal(env, 0);      qemu_kvm_eat_signals(env);
     qemu_wait_io_event_common(env);      qemu_wait_io_event_common(env);
 }  }
   
 static int qemu_cpu_exec(CPUState *env);  static void *qemu_kvm_cpu_thread_fn(void *arg)
   
 static void *kvm_cpu_thread_fn(void *arg)  
 {  {
     CPUState *env = arg;      CPUState *env = arg;
       int r;
   
     qemu_mutex_lock(&qemu_global_mutex);      qemu_mutex_lock(&qemu_global_mutex);
     qemu_thread_self(env->thread);      qemu_thread_get_self(env->thread);
     if (kvm_enabled())      env->thread_id = qemu_get_thread_id();
         kvm_init_vcpu(env);  
   
     kvm_init_ipi(env);      r = kvm_init_vcpu(env);
       if (r < 0) {
           fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r));
           exit(1);
       }
   
       qemu_kvm_init_cpu_signals(env);
   
     /* signal CPU creation */      /* signal CPU creation */
     env->created = 1;      env->created = 1;
     qemu_cond_signal(&qemu_cpu_cond);      qemu_cond_signal(&qemu_cpu_cond);
   
     /* and wait for machine initialization */      /* and wait for machine initialization */
     while (!qemu_system_ready)      while (!qemu_system_ready) {
         qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);          qemu_cond_wait(&qemu_system_cond, &qemu_global_mutex);
       }
   
     while (1) {      while (1) {
         if (cpu_can_run(env))          if (cpu_can_run(env)) {
             qemu_cpu_exec(env);              r = kvm_cpu_exec(env);
               if (r == EXCP_DEBUG) {
                   cpu_handle_guest_debug(env);
               }
           }
         qemu_kvm_wait_io_event(env);          qemu_kvm_wait_io_event(env);
     }      }
   
     return NULL;      return NULL;
 }  }
   
 static void *tcg_cpu_thread_fn(void *arg)  static void *qemu_tcg_cpu_thread_fn(void *arg)
 {  {
     CPUState *env = arg;      CPUState *env = arg;
   
     tcg_init_ipi();      qemu_tcg_init_cpu_signals();
     qemu_thread_self(env->thread);      qemu_thread_get_self(env->thread);
   
     /* signal CPU creation */      /* signal CPU creation */
     qemu_mutex_lock(&qemu_global_mutex);      qemu_mutex_lock(&qemu_global_mutex);
     for (env = first_cpu; env != NULL; env = env->next_cpu)      for (env = first_cpu; env != NULL; env = env->next_cpu) {
           env->thread_id = qemu_get_thread_id();
         env->created = 1;          env->created = 1;
       }
     qemu_cond_signal(&qemu_cpu_cond);      qemu_cond_signal(&qemu_cpu_cond);
   
     /* and wait for machine initialization */      /* and wait for machine initialization */
     while (!qemu_system_ready)      while (!qemu_system_ready) {
         qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);          qemu_cond_wait(&qemu_system_cond, &qemu_global_mutex);
       }
   
     while (1) {      while (1) {
         cpu_exec_all();          cpu_exec_all();
           if (use_icount && qemu_next_icount_deadline() <= 0) {
               qemu_notify_event();
           }
         qemu_tcg_wait_io_event();          qemu_tcg_wait_io_event();
     }      }
   
     return NULL;      return NULL;
 }  }
   
 void qemu_cpu_kick(void *_env)  static void qemu_cpu_kick_thread(CPUState *env)
 {  
     CPUState *env = _env;  
     qemu_cond_broadcast(env->halt_cond);  
     qemu_thread_signal(env->thread, SIG_IPI);  
 }  
   
 int qemu_cpu_self(void *_env)  
 {  {
     CPUState *env = _env;  #ifndef _WIN32
     QemuThread this;      int err;
   
     qemu_thread_self(&this);  
   
     return qemu_thread_equal(&this, env->thread);  
 }  
   
 static void cpu_signal(int sig)      err = pthread_kill(env->thread->thread, SIG_IPI);
 {      if (err) {
     if (cpu_single_env)          fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
         cpu_exit(cpu_single_env);          exit(1);
     exit_request = 1;      }
   #else /* _WIN32 */
       if (!qemu_cpu_is_self(env)) {
           SuspendThread(env->thread->thread);
           cpu_signal(0);
           ResumeThread(env->thread->thread);
       }
   #endif
 }  }
   
 static void tcg_init_ipi(void)  void qemu_cpu_kick(void *_env)
 {  {
     sigset_t set;      CPUState *env = _env;
     struct sigaction sigact;  
   
     memset(&sigact, 0, sizeof(sigact));  
     sigact.sa_handler = cpu_signal;  
     sigaction(SIG_IPI, &sigact, NULL);  
   
     sigemptyset(&set);  
     sigaddset(&set, SIG_IPI);  
     pthread_sigmask(SIG_UNBLOCK, &set, NULL);  
 }  
   
 static void dummy_signal(int sig)      qemu_cond_broadcast(env->halt_cond);
 {      if (!env->thread_kicked) {
           qemu_cpu_kick_thread(env);
           env->thread_kicked = true;
       }
 }  }
   
 static void kvm_init_ipi(CPUState *env)  void qemu_cpu_kick_self(void)
 {  {
     int r;  #ifndef _WIN32
     sigset_t set;      assert(cpu_single_env);
     struct sigaction sigact;  
   
     memset(&sigact, 0, sizeof(sigact));  
     sigact.sa_handler = dummy_signal;  
     sigaction(SIG_IPI, &sigact, NULL);  
   
     pthread_sigmask(SIG_BLOCK, NULL, &set);      if (!cpu_single_env->thread_kicked) {
     sigdelset(&set, SIG_IPI);          qemu_cpu_kick_thread(cpu_single_env);
     sigdelset(&set, SIGBUS);          cpu_single_env->thread_kicked = true;
     r = kvm_set_signal_mask(env, &set);  
     if (r) {  
         fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));  
         exit(1);  
     }      }
   #else
       abort();
   #endif
 }  }
   
 static sigset_t block_io_signals(void)  int qemu_cpu_is_self(void *_env)
 {  {
     sigset_t set;      CPUState *env = _env;
     struct sigaction action;  
   
     /* SIGUSR2 used by posix-aio-compat.c */  
     sigemptyset(&set);  
     sigaddset(&set, SIGUSR2);  
     pthread_sigmask(SIG_UNBLOCK, &set, NULL);  
   
     sigemptyset(&set);  
     sigaddset(&set, SIGIO);  
     sigaddset(&set, SIGALRM);  
     sigaddset(&set, SIG_IPI);  
     sigaddset(&set, SIGBUS);  
     pthread_sigmask(SIG_BLOCK, &set, NULL);  
   
     memset(&action, 0, sizeof(action));  
     action.sa_flags = SA_SIGINFO;  
     action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;  
     sigaction(SIGBUS, &action, NULL);  
     prctl(PR_MCE_KILL, 1, 1, 0, 0);  
   
     return set;      return qemu_thread_is_self(env->thread);
 }  }
   
 void qemu_mutex_lock_iothread(void)  void qemu_mutex_lock_iothread(void)
Line 737  void qemu_mutex_lock_iothread(void) Line 901  void qemu_mutex_lock_iothread(void)
     if (kvm_enabled()) {      if (kvm_enabled()) {
         qemu_mutex_lock(&qemu_global_mutex);          qemu_mutex_lock(&qemu_global_mutex);
     } else {      } else {
         qemu_mutex_lock(&qemu_fair_mutex);          iothread_requesting_mutex = true;
         if (qemu_mutex_trylock(&qemu_global_mutex)) {          if (qemu_mutex_trylock(&qemu_global_mutex)) {
             qemu_thread_signal(tcg_cpu_thread, SIG_IPI);              qemu_cpu_kick_thread(first_cpu);
             qemu_mutex_lock(&qemu_global_mutex);              qemu_mutex_lock(&qemu_global_mutex);
         }          }
         qemu_mutex_unlock(&qemu_fair_mutex);          iothread_requesting_mutex = false;
           qemu_cond_broadcast(&qemu_io_proceeded_cond);
     }      }
 }  }
   
Line 756  static int all_vcpus_paused(void) Line 921  static int all_vcpus_paused(void)
     CPUState *penv = first_cpu;      CPUState *penv = first_cpu;
   
     while (penv) {      while (penv) {
         if (!penv->stopped)          if (!penv->stopped) {
             return 0;              return 0;
           }
         penv = (CPUState *)penv->next_cpu;          penv = (CPUState *)penv->next_cpu;
     }      }
   
Line 775  void pause_all_vcpus(void) Line 941  void pause_all_vcpus(void)
     }      }
   
     while (!all_vcpus_paused()) {      while (!all_vcpus_paused()) {
         qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);          qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
         penv = first_cpu;          penv = first_cpu;
         while (penv) {          while (penv) {
             qemu_cpu_kick(penv);              qemu_cpu_kick(penv);
Line 796  void resume_all_vcpus(void) Line 962  void resume_all_vcpus(void)
     }      }
 }  }
   
 static void tcg_init_vcpu(void *_env)  static void qemu_tcg_init_vcpu(void *_env)
 {  {
     CPUState *env = _env;      CPUState *env = _env;
   
     /* share a single thread for all cpus with TCG */      /* share a single thread for all cpus with TCG */
     if (!tcg_cpu_thread) {      if (!tcg_cpu_thread) {
         env->thread = qemu_mallocz(sizeof(QemuThread));          env->thread = qemu_mallocz(sizeof(QemuThread));
         env->halt_cond = qemu_mallocz(sizeof(QemuCond));          env->halt_cond = qemu_mallocz(sizeof(QemuCond));
         qemu_cond_init(env->halt_cond);          qemu_cond_init(env->halt_cond);
         qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);          qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env);
         while (env->created == 0)          while (env->created == 0) {
             qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);              qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
           }
         tcg_cpu_thread = env->thread;          tcg_cpu_thread = env->thread;
         tcg_halt_cond = env->halt_cond;          tcg_halt_cond = env->halt_cond;
     } else {      } else {
Line 815  static void tcg_init_vcpu(void *_env) Line 983  static void tcg_init_vcpu(void *_env)
     }      }
 }  }
   
 static void kvm_start_vcpu(CPUState *env)  static void qemu_kvm_start_vcpu(CPUState *env)
 {  {
     env->thread = qemu_mallocz(sizeof(QemuThread));      env->thread = qemu_mallocz(sizeof(QemuThread));
     env->halt_cond = qemu_mallocz(sizeof(QemuCond));      env->halt_cond = qemu_mallocz(sizeof(QemuCond));
     qemu_cond_init(env->halt_cond);      qemu_cond_init(env->halt_cond);
     qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);      qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env);
     while (env->created == 0)      while (env->created == 0) {
         qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);          qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
       }
 }  }
   
 void qemu_init_vcpu(void *_env)  void qemu_init_vcpu(void *_env)
Line 831  void qemu_init_vcpu(void *_env) Line 1000  void qemu_init_vcpu(void *_env)
   
     env->nr_cores = smp_cores;      env->nr_cores = smp_cores;
     env->nr_threads = smp_threads;      env->nr_threads = smp_threads;
     if (kvm_enabled())      if (kvm_enabled()) {
         kvm_start_vcpu(env);          qemu_kvm_start_vcpu(env);
     else      } else {
         tcg_init_vcpu(env);          qemu_tcg_init_vcpu(env);
       }
 }  }
   
 void qemu_notify_event(void)  void qemu_notify_event(void)
Line 842  void qemu_notify_event(void) Line 1012  void qemu_notify_event(void)
     qemu_event_increment();      qemu_event_increment();
 }  }
   
 static void qemu_system_vmstop_request(int reason)  void cpu_stop_current(void)
 {  {
     vmstop_requested = reason;      if (cpu_single_env) {
     qemu_notify_event();          cpu_single_env->stop = 0;
           cpu_single_env->stopped = 1;
           cpu_exit(cpu_single_env);
           qemu_cond_signal(&qemu_pause_cond);
       }
 }  }
   
 void vm_stop(int reason)  void vm_stop(int reason)
 {  {
     QemuThread me;      if (!qemu_thread_is_self(&io_thread)) {
     qemu_thread_self(&me);  
   
     if (!qemu_thread_equal(&me, &io_thread)) {  
         qemu_system_vmstop_request(reason);          qemu_system_vmstop_request(reason);
         /*          /*
          * FIXME: should not return to device code in case           * FIXME: should not return to device code in case
          * vm_stop() has been requested.           * vm_stop() has been requested.
          */           */
         if (cpu_single_env) {          cpu_stop_current();
             cpu_exit(cpu_single_env);  
             cpu_single_env->stop = 1;  
         }  
         return;          return;
     }      }
     do_vm_stop(reason);      do_vm_stop(reason);
Line 870  void vm_stop(int reason) Line 1038  void vm_stop(int reason)
   
 #endif  #endif
   
 static int qemu_cpu_exec(CPUState *env)  static int tcg_cpu_exec(CPUState *env)
 {  {
     int ret;      int ret;
 #ifdef CONFIG_PROFILER  #ifdef CONFIG_PROFILER
Line 886  static int qemu_cpu_exec(CPUState *env) Line 1054  static int qemu_cpu_exec(CPUState *env)
         qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);          qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
         env->icount_decr.u16.low = 0;          env->icount_decr.u16.low = 0;
         env->icount_extra = 0;          env->icount_extra = 0;
         count = qemu_icount_round (qemu_next_deadline());          count = qemu_icount_round(qemu_next_icount_deadline());
         qemu_icount += count;          qemu_icount += count;
         decr = (count > 0xffff) ? 0xffff : count;          decr = (count > 0xffff) ? 0xffff : count;
         count -= decr;          count -= decr;
Line 910  static int qemu_cpu_exec(CPUState *env) Line 1078  static int qemu_cpu_exec(CPUState *env)
   
 bool cpu_exec_all(void)  bool cpu_exec_all(void)
 {  {
     if (next_cpu == NULL)      int r;
   
       /* Account partial waits to the vm_clock.  */
       qemu_clock_warp(vm_clock);
   
       if (next_cpu == NULL) {
         next_cpu = first_cpu;          next_cpu = first_cpu;
       }
     for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {      for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
         CPUState *env = next_cpu;          CPUState *env = next_cpu;
   
         qemu_clock_enable(vm_clock,          qemu_clock_enable(vm_clock,
                           (env->singlestep_enabled & SSTEP_NOTIMER) == 0);                            (env->singlestep_enabled & SSTEP_NOTIMER) == 0);
   
         if (qemu_alarm_pending())  #ifndef CONFIG_IOTHREAD
           if (qemu_alarm_pending()) {
             break;              break;
           }
   #endif
         if (cpu_can_run(env)) {          if (cpu_can_run(env)) {
             if (qemu_cpu_exec(env) == EXCP_DEBUG) {              if (kvm_enabled()) {
                   r = kvm_cpu_exec(env);
                   qemu_kvm_eat_signals(env);
               } else {
                   r = tcg_cpu_exec(env);
               }
               if (r == EXCP_DEBUG) {
                   cpu_handle_guest_debug(env);
                 break;                  break;
             }              }
         } else if (env->stop) {          } else if (env->stop || env->stopped) {
             break;              break;
         }          }
     }      }
     exit_request = 0;      exit_request = 0;
     return any_cpu_has_work();      return !all_cpu_threads_idle();
 }  }
   
 void set_numa_modes(void)  void set_numa_modes(void)
Line 962  void set_cpu_log(const char *optarg) Line 1146  void set_cpu_log(const char *optarg)
     cpu_set_log(mask);      cpu_set_log(mask);
 }  }
   
   void set_cpu_log_filename(const char *optarg)
   {
       cpu_set_log_filename(optarg);
   }
   
 /* Return the virtual CPU time, based on the instruction counter.  */  /* Return the virtual CPU time, based on the instruction counter.  */
 int64_t cpu_get_icount(void)  int64_t cpu_get_icount(void)
 {  {

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


unix.superglobalmegacorp.com