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 #include <sys/syscall.h> 20 21 struct sigfd_compat_info 22 { 23 sigset_t mask; 24 int fd; 25 }; 26 27 static void *sigwait_compat(void *opaque) 28 { 29 struct sigfd_compat_info *info = opaque; 30 31 while (1) { 32 int sig; 33 int err; 34 35 err = sigwait(&info->mask, &sig); 36 if (err != 0) { 37 if (errno == EINTR) { 38 continue; 39 } else { 40 return NULL; 41 } 42 } else { 43 struct qemu_signalfd_siginfo buffer; 44 size_t offset = 0; 45 46 memset(&buffer, 0, sizeof(buffer)); 47 buffer.ssi_signo = sig; 48 49 while (offset < sizeof(buffer)) { 50 ssize_t len; 51 52 len = write(info->fd, (char *)&buffer + offset, 53 sizeof(buffer) - offset); 54 if (len == -1 && errno == EINTR) 55 continue; 56 57 if (len <= 0) { 58 return NULL; 59 } 60 61 offset += len; 62 } 63 } 64 } 65 } 66 67 static int qemu_signalfd_compat(const sigset_t *mask) 68 { 69 struct sigfd_compat_info *info; 70 QemuThread thread; 71 int fds[2]; 72 73 info = malloc(sizeof(*info)); 74 if (info == NULL) { 75 errno = ENOMEM; 76 return -1; 77 } 78 79 if (pipe(fds) == -1) { 80 free(info); 81 return -1; 82 } 83 84 qemu_set_cloexec(fds[0]); 85 qemu_set_cloexec(fds[1]); 86 87 memcpy(&info->mask, mask, sizeof(*mask)); 88 info->fd = fds[1]; 89 90 qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, 91 QEMU_THREAD_DETACHED); 92 93 return fds[0]; 94 } 95 96 int qemu_signalfd(const sigset_t *mask) 97 { 98 #if defined(CONFIG_SIGNALFD) 99 int ret; 100 101 ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8); 102 if (ret != -1) { 103 qemu_set_cloexec(ret); 104 return ret; 105 } 106 #endif 107 108 return qemu_signalfd_compat(mask); 109 } 110