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 memset(&buffer, 0, sizeof(buffer)); 46 buffer.ssi_signo = sig; 47 48 if (qemu_write_full(info->fd, &buffer, sizeof(buffer)) != sizeof(buffer)) { 49 return NULL; 50 } 51 } 52 } 53 } 54 55 static int qemu_signalfd_compat(const sigset_t *mask) 56 { 57 struct sigfd_compat_info *info; 58 QemuThread thread; 59 int fds[2]; 60 61 info = g_malloc(sizeof(*info)); 62 63 if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) { 64 g_free(info); 65 return -1; 66 } 67 68 memcpy(&info->mask, mask, sizeof(*mask)); 69 info->fd = fds[1]; 70 71 qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, 72 QEMU_THREAD_DETACHED); 73 74 return fds[0]; 75 } 76 77 int qemu_signalfd(const sigset_t *mask) 78 { 79 #if defined(CONFIG_SIGNALFD) 80 int ret; 81 82 ret = signalfd(-1, mask, SFD_CLOEXEC); 83 if (ret != -1) { 84 return ret; 85 } 86 #endif 87 88 return qemu_signalfd_compat(mask); 89 } 90