| /* | 
 |  * signalfd/eventfd compatibility | 
 |  * | 
 |  * Copyright IBM, Corp. 2008 | 
 |  * | 
 |  * Authors: | 
 |  *  Anthony Liguori   <aliguori@us.ibm.com> | 
 |  * | 
 |  * This work is licensed under the terms of the GNU GPL, version 2.  See | 
 |  * the COPYING file in the top-level directory. | 
 |  * | 
 |  * Contributions after 2012-01-13 are licensed under the terms of the | 
 |  * GNU GPL, version 2 or (at your option) any later version. | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "qemu/thread.h" | 
 |  | 
 | #if defined(CONFIG_SIGNALFD) | 
 | #include <sys/signalfd.h> | 
 | #endif | 
 |  | 
 | struct sigfd_compat_info { | 
 |     sigset_t mask; | 
 |     int fd; | 
 | }; | 
 |  | 
 | static void *sigwait_compat(void *opaque) | 
 | { | 
 |     struct sigfd_compat_info *info = opaque; | 
 |  | 
 |     while (1) { | 
 |         int sig; | 
 |         int err; | 
 |  | 
 |         err = sigwait(&info->mask, &sig); | 
 |         if (err != 0) { | 
 |             if (errno == EINTR) { | 
 |                 continue; | 
 |             } else { | 
 |                 return NULL; | 
 |             } | 
 |         } else { | 
 |             struct qemu_signalfd_siginfo buffer; | 
 |             memset(&buffer, 0, sizeof(buffer)); | 
 |             buffer.ssi_signo = sig; | 
 |  | 
 |             if (qemu_write_full(info->fd, &buffer, sizeof(buffer)) != sizeof(buffer)) { | 
 |                 return NULL; | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | static int qemu_signalfd_compat(const sigset_t *mask) | 
 | { | 
 |     struct sigfd_compat_info *info; | 
 |     QemuThread thread; | 
 |     int fds[2]; | 
 |  | 
 |     info = g_malloc(sizeof(*info)); | 
 |  | 
 |     if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) { | 
 |         g_free(info); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     memcpy(&info->mask, mask, sizeof(*mask)); | 
 |     info->fd = fds[1]; | 
 |  | 
 |     qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, | 
 |                        QEMU_THREAD_DETACHED); | 
 |  | 
 |     return fds[0]; | 
 | } | 
 |  | 
 | int qemu_signalfd(const sigset_t *mask) | 
 | { | 
 | #if defined(CONFIG_SIGNALFD) | 
 |     int ret; | 
 |  | 
 |     ret = signalfd(-1, mask, SFD_CLOEXEC); | 
 |     if (ret != -1) { | 
 |         return ret; | 
 |     } | 
 | #endif | 
 |  | 
 |     return qemu_signalfd_compat(mask); | 
 | } |