1 /* 2 * signalfd/eventfd compatibility 3 * 4 * Copyright IBM, Corp. 2008 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 * Contributions after 2012-01-13 are licensed under the terms of the 13 * GNU GPL, version 2 or (at your option) any later version. 14 */ 15 16 #include "qemu-common.h" 17 #include "qemu/compatfd.h" 18 #include "qemu/thread.h" 19 20 #include <sys/syscall.h> 21 22 struct sigfd_compat_info 23 { 24 sigset_t mask; 25 int fd; 26 }; 27 28 static void *sigwait_compat(void *opaque) 29 { 30 struct sigfd_compat_info *info = opaque; 31 32 while (1) { 33 int sig; 34 int err; 35 36 err = sigwait(&info->mask, &sig); 37 if (err != 0) { 38 if (errno == EINTR) { 39 continue; 40 } else { 41 return NULL; 42 } 43 } else { 44 struct qemu_signalfd_siginfo buffer; 45 size_t offset = 0; 46 47 memset(&buffer, 0, sizeof(buffer)); 48 buffer.ssi_signo = sig; 49 50 while (offset < sizeof(buffer)) { 51 ssize_t len; 52 53 len = write(info->fd, (char *)&buffer + offset, 54 sizeof(buffer) - offset); 55 if (len == -1 && errno == EINTR) 56 continue; 57 58 if (len <= 0) { 59 return NULL; 60 } 61 62 offset += len; 63 } 64 } 65 } 66 } 67 68 static int qemu_signalfd_compat(const sigset_t *mask) 69 { 70 struct sigfd_compat_info *info; 71 QemuThread thread; 72 int fds[2]; 73 74 info = malloc(sizeof(*info)); 75 if (info == NULL) { 76 errno = ENOMEM; 77 return -1; 78 } 79 80 if (pipe(fds) == -1) { 81 free(info); 82 return -1; 83 } 84 85 qemu_set_cloexec(fds[0]); 86 qemu_set_cloexec(fds[1]); 87 88 memcpy(&info->mask, mask, sizeof(*mask)); 89 info->fd = fds[1]; 90 91 qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, 92 QEMU_THREAD_DETACHED); 93 94 return fds[0]; 95 } 96 97 int qemu_signalfd(const sigset_t *mask) 98 { 99 #if defined(CONFIG_SIGNALFD) 100 int ret; 101 102 ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8); 103 if (ret != -1) { 104 qemu_set_cloexec(ret); 105 return ret; 106 } 107 #endif 108 109 return qemu_signalfd_compat(mask); 110 } 111 112 bool qemu_signalfd_available(void) 113 { 114 #ifdef CONFIG_SIGNALFD 115 sigset_t mask; 116 int fd; 117 bool ok; 118 sigemptyset(&mask); 119 errno = 0; 120 fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8); 121 ok = (errno != ENOSYS); 122 if (fd >= 0) { 123 close(fd); 124 } 125 return ok; 126 #else 127 return false; 128 #endif 129 } 130