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/signalfd.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 = g_malloc(sizeof(*info)); 76 77 if (pipe(fds) == -1) { 78 g_free(info); 79 return -1; 80 } 81 82 qemu_set_cloexec(fds[0]); 83 qemu_set_cloexec(fds[1]); 84 85 memcpy(&info->mask, mask, sizeof(*mask)); 86 info->fd = fds[1]; 87 88 qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, 89 QEMU_THREAD_DETACHED); 90 91 return fds[0]; 92 } 93 94 int qemu_signalfd(const sigset_t *mask) 95 { 96 #if defined(CONFIG_SIGNALFD) 97 int ret; 98 99 ret = signalfd(-1, mask, SFD_CLOEXEC); 100 if (ret != -1) { 101 return ret; 102 } 103 #endif 104 105 return qemu_signalfd_compat(mask); 106 } 107