qemu/util/compatfd.c
<<
>>
Prefs
   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
  21struct sigfd_compat_info
  22{
  23    sigset_t mask;
  24    int fd;
  25};
  26
  27static 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
  67static 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
  96int 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