qemu/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-common.h"
  17#include "compatfd.h"
  18
  19#include <sys/syscall.h>
  20#include <pthread.h>
  21
  22struct sigfd_compat_info
  23{
  24    sigset_t mask;
  25    int fd;
  26};
  27
  28static void *sigwait_compat(void *opaque)
  29{
  30    struct sigfd_compat_info *info = opaque;
  31    sigset_t all;
  32
  33    sigfillset(&all);
  34    pthread_sigmask(SIG_BLOCK, &all, NULL);
  35
  36    while (1) {
  37        int sig;
  38        int err;
  39
  40        err = sigwait(&info->mask, &sig);
  41        if (err != 0) {
  42            if (errno == EINTR) {
  43                continue;
  44            } else {
  45                return NULL;
  46            }
  47        } else {
  48            struct qemu_signalfd_siginfo buffer;
  49            size_t offset = 0;
  50
  51            memset(&buffer, 0, sizeof(buffer));
  52            buffer.ssi_signo = sig;
  53
  54            while (offset < sizeof(buffer)) {
  55                ssize_t len;
  56
  57                len = write(info->fd, (char *)&buffer + offset,
  58                            sizeof(buffer) - offset);
  59                if (len == -1 && errno == EINTR)
  60                    continue;
  61
  62                if (len <= 0) {
  63                    return NULL;
  64                }
  65
  66                offset += len;
  67            }
  68        }
  69    }
  70}
  71
  72static int qemu_signalfd_compat(const sigset_t *mask)
  73{
  74    pthread_attr_t attr;
  75    pthread_t tid;
  76    struct sigfd_compat_info *info;
  77    int fds[2];
  78
  79    info = malloc(sizeof(*info));
  80    if (info == NULL) {
  81        errno = ENOMEM;
  82        return -1;
  83    }
  84
  85    if (pipe(fds) == -1) {
  86        free(info);
  87        return -1;
  88    }
  89
  90    qemu_set_cloexec(fds[0]);
  91    qemu_set_cloexec(fds[1]);
  92
  93    memcpy(&info->mask, mask, sizeof(*mask));
  94    info->fd = fds[1];
  95
  96    pthread_attr_init(&attr);
  97    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  98
  99    pthread_create(&tid, &attr, sigwait_compat, info);
 100
 101    pthread_attr_destroy(&attr);
 102
 103    return fds[0];
 104}
 105
 106int qemu_signalfd(const sigset_t *mask)
 107{
 108#if defined(CONFIG_SIGNALFD)
 109    int ret;
 110
 111    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
 112    if (ret != -1) {
 113        qemu_set_cloexec(ret);
 114        return ret;
 115    }
 116#endif
 117
 118    return qemu_signalfd_compat(mask);
 119}
 120
 121bool qemu_signalfd_available(void)
 122{
 123#ifdef CONFIG_SIGNALFD
 124    sigset_t mask;
 125    int fd;
 126    bool ok;
 127    sigemptyset(&mask);
 128    errno = 0;
 129    fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
 130    ok = (errno != ENOSYS);
 131    if (fd >= 0) {
 132        close(fd);
 133    }
 134    return ok;
 135#else
 136    return false;
 137#endif
 138}
 139