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-common.h" 18 #include "qemu/compatfd.h" 19 #include "qemu/thread.h" 20 21 #include <sys/syscall.h> 22 23 struct sigfd_compat_info 24 { 25 sigset_t mask; 26 int fd; 27 }; 28 29 static void *sigwait_compat(void *opaque) 30 { 31 struct sigfd_compat_info *info = opaque; 32 33 while (1) { 34 int sig; 35 int err; 36 37 err = sigwait(&info->mask, &sig); 38 if (err != 0) { 39 if (errno == EINTR) { 40 continue; 41 } else { 42 return NULL; 43 } 44 } else { 45 struct qemu_signalfd_siginfo buffer; 46 size_t offset = 0; 47 48 memset(&buffer, 0, sizeof(buffer)); 49 buffer.ssi_signo = sig; 50 51 while (offset < sizeof(buffer)) { 52 ssize_t len; 53 54 len = write(info->fd, (char *)&buffer + offset, 55 sizeof(buffer) - offset); 56 if (len == -1 && errno == EINTR) 57 continue; 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