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/osdep.h" 17 #include "qemu/thread.h" 18 19 #if defined(CONFIG_SIGNALFD) 20 #include <sys/syscall.h> 21 #endif 22 23 struct sigfd_compat_info { 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 59 if (len <= 0) { 60 return NULL; 61 } 62 63 offset += len; 64 } 65 } 66 } 67 } 68 69 static int qemu_signalfd_compat(const sigset_t *mask) 70 { 71 struct sigfd_compat_info *info; 72 QemuThread thread; 73 int fds[2]; 74 75 info = malloc(sizeof(*info)); 76 if (info == NULL) { 77 errno = ENOMEM; 78 return -1; 79 } 80 81 if (pipe(fds) == -1) { 82 free(info); 83 return -1; 84 } 85 86 qemu_set_cloexec(fds[0]); 87 qemu_set_cloexec(fds[1]); 88 89 memcpy(&info->mask, mask, sizeof(*mask)); 90 info->fd = fds[1]; 91 92 qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, 93 QEMU_THREAD_DETACHED); 94 95 return fds[0]; 96 } 97 98 int qemu_signalfd(const sigset_t *mask) 99 { 100 #if defined(CONFIG_SIGNALFD) 101 int ret; 102 103 ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8); 104 if (ret != -1) { 105 qemu_set_cloexec(ret); 106 return ret; 107 } 108 #endif 109 110 return qemu_signalfd_compat(mask); 111 } 112