]> git.proxmox.com Git - qemu.git/commitdiff
Register Linux dyntick timer as per-thread signal
authorJan Kiszka <jan.kiszka@siemens.com>
Fri, 17 Jun 2011 09:25:49 +0000 (11:25 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Sat, 23 Jul 2011 16:26:12 +0000 (11:26 -0500)
Derived from kvm-tool patch
http://thread.gmane.org/gmane.comp.emulators.kvm.devel/74309

Ingo Molnar pointed out that sending the timer signal to the whole
process, just blocking it everywhere, is suboptimal with an increasing
number of threads. QEMU is also using this pattern so far.

Linux provides a (non-portable) way to restrict the signal to a single
thread: We can use SIGEV_THREAD_ID unless we are forced to emulate
signalfd via an additional thread. That case could theoretically be
optimized as well, but it doesn't look worth bothering.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
compatfd.c
compatfd.h
qemu-timer.c

index 41586ceaea969e1eef23c17ec8214a3aa5a3f8ff..31654c62a690aff68d7350bbe96ed80391e36b7a 100644 (file)
@@ -115,3 +115,14 @@ int qemu_signalfd(const sigset_t *mask)
 
     return qemu_signalfd_compat(mask);
 }
+
+bool qemu_signalfd_available(void)
+{
+#ifdef CONFIG_SIGNALFD
+    errno = 0;
+    syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
+    return errno != ENOSYS;
+#else
+    return false;
+#endif
+}
index fc3791520f3209a074d1f0b8b210940692bb836d..6b04877b97063381fb7c51bcdaaf69c938a35f68 100644 (file)
@@ -39,5 +39,6 @@ struct qemu_signalfd_siginfo {
 };
 
 int qemu_signalfd(const sigset_t *mask);
+bool qemu_signalfd_available(void);
 
 #endif
index f95374c7c1a732223f4b4d761b82bf7bd5ce5a8f..30e8f1272e8c6ab4fca20931c38a979d52417133 100644 (file)
@@ -831,6 +831,8 @@ static int64_t qemu_next_alarm_deadline(void)
 
 #if defined(__linux__)
 
+#include "compatfd.h"
+
 static int dynticks_start_timer(struct qemu_alarm_timer *t)
 {
     struct sigevent ev;
@@ -850,6 +852,12 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t)
     memset(&ev, 0, sizeof(ev));
     ev.sigev_value.sival_int = 0;
     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;
 
     if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {