]>
Commit | Line | Data |
---|---|---|
dcc38d1c MT |
1 | /* |
2 | * signalfd/eventfd compatibility | |
3 | * | |
4 | * Copyright IBM, Corp. 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <[email protected]> | |
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 | * | |
6b620ca3 PB |
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. | |
dcc38d1c MT |
14 | */ |
15 | ||
aafd7584 | 16 | #include "qemu/osdep.h" |
dcc38d1c | 17 | #include "qemu-common.h" |
1de7afc9 | 18 | #include "qemu/compatfd.h" |
518420df | 19 | #include "qemu/thread.h" |
dcc38d1c MT |
20 | |
21 | #include <sys/syscall.h> | |
dcc38d1c MT |
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; | |
dcc38d1c | 32 | |
30faaf70 TG |
33 | while (1) { |
34 | int sig; | |
35 | int err; | |
dcc38d1c | 36 | |
30faaf70 TG |
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; | |
dcc38d1c MT |
46 | size_t offset = 0; |
47 | ||
30faaf70 TG |
48 | memset(&buffer, 0, sizeof(buffer)); |
49 | buffer.ssi_signo = sig; | |
50 | ||
dcc38d1c MT |
51 | while (offset < sizeof(buffer)) { |
52 | ssize_t len; | |
53 | ||
30faaf70 | 54 | len = write(info->fd, (char *)&buffer + offset, |
dcc38d1c MT |
55 | sizeof(buffer) - offset); |
56 | if (len == -1 && errno == EINTR) | |
57 | continue; | |
58 | ||
59 | if (len <= 0) { | |
30faaf70 | 60 | return NULL; |
dcc38d1c MT |
61 | } |
62 | ||
63 | offset += len; | |
64 | } | |
65 | } | |
30faaf70 | 66 | } |
dcc38d1c MT |
67 | } |
68 | ||
69 | static int qemu_signalfd_compat(const sigset_t *mask) | |
70 | { | |
dcc38d1c | 71 | struct sigfd_compat_info *info; |
518420df | 72 | QemuThread thread; |
dcc38d1c MT |
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 | ||
4900116e DDAG |
92 | qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, |
93 | QEMU_THREAD_DETACHED); | |
dcc38d1c MT |
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 | } |