• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
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 
sigwait_compat(void * opaque)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 
qemu_signalfd_compat(const sigset_t * mask)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 
qemu_signalfd(const sigset_t * mask)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