]>
Commit | Line | Data |
---|---|---|
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 | * | |
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 | } |