Home | History | Annotate | Download | only in qemu
      1 /*
      2  * signalfd/eventfd compatibility
      3  *
      4  * Copyright IBM, Corp. 2008
      5  *
      6  * Authors:
      7  *  Anthony Liguori   <aliguori (at) 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  */
     13 
     14 #include "qemu-common.h"
     15 #include "compatfd.h"
     16 
     17 #include <sys/syscall.h>
     18 #include <pthread.h>
     19 
     20 struct sigfd_compat_info
     21 {
     22     sigset_t mask;
     23     int fd;
     24 };
     25 
     26 static void *sigwait_compat(void *opaque)
     27 {
     28     struct sigfd_compat_info *info = opaque;
     29     sigset_t all;
     30 
     31     sigfillset(&all);
     32     sigprocmask(SIG_BLOCK, &all, NULL);
     33 
     34     while (1) {
     35         int sig;
     36         int err;
     37 
     38         err = sigwait(&info->mask, &sig);
     39         if (err != 0) {
     40             if (errno == EINTR) {
     41                 continue;
     42             } else {
     43                 return NULL;
     44             }
     45         } else {
     46             struct qemu_signalfd_siginfo buffer;
     47             size_t offset = 0;
     48 
     49             memset(&buffer, 0, sizeof(buffer));
     50             buffer.ssi_signo = sig;
     51 
     52             while (offset < sizeof(buffer)) {
     53                 ssize_t len;
     54 
     55                 len = write(info->fd, (char *)&buffer + offset,
     56                             sizeof(buffer) - offset);
     57                 if (len == -1 && errno == EINTR)
     58                     continue;
     59 
     60                 if (len <= 0) {
     61                     return NULL;
     62                 }
     63 
     64                 offset += len;
     65             }
     66         }
     67     }
     68 }
     69 
     70 static int qemu_signalfd_compat(const sigset_t *mask)
     71 {
     72     pthread_attr_t attr;
     73     pthread_t tid;
     74     struct sigfd_compat_info *info;
     75     int fds[2];
     76 
     77     info = malloc(sizeof(*info));
     78     if (info == NULL) {
     79         errno = ENOMEM;
     80         return -1;
     81     }
     82 
     83     if (pipe(fds) == -1) {
     84         free(info);
     85         return -1;
     86     }
     87 
     88     qemu_set_cloexec(fds[0]);
     89     qemu_set_cloexec(fds[1]);
     90 
     91     memcpy(&info->mask, mask, sizeof(*mask));
     92     info->fd = fds[1];
     93 
     94     pthread_attr_init(&attr);
     95     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
     96 
     97     pthread_create(&tid, &attr, sigwait_compat, info);
     98 
     99     pthread_attr_destroy(&attr);
    100 
    101     return fds[0];
    102 }
    103 
    104 int qemu_signalfd(const sigset_t *mask)
    105 {
    106 #if defined(CONFIG_SIGNALFD)
    107     int ret;
    108 
    109     ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
    110     if (ret != -1) {
    111         qemu_set_cloexec(ret);
    112         return ret;
    113     }
    114 #endif
    115 
    116     return qemu_signalfd_compat(mask);
    117 }
    118