xref: /openbmc/qemu/util/compatfd.c (revision bcad45de)
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-common.h"
18  #include "qemu/compatfd.h"
19  #include "qemu/thread.h"
20  
21  #include <sys/syscall.h>
22  
23  struct sigfd_compat_info
24  {
25      sigset_t mask;
26      int fd;
27  };
28  
29  static void *sigwait_compat(void *opaque)
30  {
31      struct sigfd_compat_info *info = opaque;
32  
33      while (1) {
34          int sig;
35          int err;
36  
37          err = sigwait(&info->mask, &sig);
38          if (err != 0) {
39              if (errno == EINTR) {
40                  continue;
41              } else {
42                  return NULL;
43              }
44          } else {
45              struct qemu_signalfd_siginfo buffer;
46              size_t offset = 0;
47  
48              memset(&buffer, 0, sizeof(buffer));
49              buffer.ssi_signo = sig;
50  
51              while (offset < sizeof(buffer)) {
52                  ssize_t len;
53  
54                  len = write(info->fd, (char *)&buffer + offset,
55                              sizeof(buffer) - offset);
56                  if (len == -1 && errno == EINTR)
57                      continue;
58  
59                  if (len <= 0) {
60                      return NULL;
61                  }
62  
63                  offset += len;
64              }
65          }
66      }
67  }
68  
69  static int qemu_signalfd_compat(const sigset_t *mask)
70  {
71      struct sigfd_compat_info *info;
72      QemuThread thread;
73      int fds[2];
74  
75      info = malloc(sizeof(*info));
76      if (info == NULL) {
77          errno = ENOMEM;
78          return -1;
79      }
80  
81      if (pipe(fds) == -1) {
82          free(info);
83          return -1;
84      }
85  
86      qemu_set_cloexec(fds[0]);
87      qemu_set_cloexec(fds[1]);
88  
89      memcpy(&info->mask, mask, sizeof(*mask));
90      info->fd = fds[1];
91  
92      qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info,
93                         QEMU_THREAD_DETACHED);
94  
95      return fds[0];
96  }
97  
98  int qemu_signalfd(const sigset_t *mask)
99  {
100  #if defined(CONFIG_SIGNALFD)
101      int ret;
102  
103      ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
104      if (ret != -1) {
105          qemu_set_cloexec(ret);
106          return ret;
107      }
108  #endif
109  
110      return qemu_signalfd_compat(mask);
111  }
112