1 | /* |
2 | * event notifier support |
3 | * |
4 | * Copyright Red Hat, Inc. 2010 |
5 | * |
6 | * Authors: |
7 | * Michael S. Tsirkin <mst@redhat.com> |
8 | * |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
10 | * See the COPYING file in the top-level directory. |
11 | */ |
12 | |
13 | #include "qemu/osdep.h" |
14 | #include "qemu-common.h" |
15 | #include "qemu/cutils.h" |
16 | #include "qemu/event_notifier.h" |
17 | #include "qemu/main-loop.h" |
18 | |
19 | #ifdef CONFIG_EVENTFD |
20 | #include <sys/eventfd.h> |
21 | #endif |
22 | |
23 | #ifdef CONFIG_EVENTFD |
24 | /* |
25 | * Initialize @e with existing file descriptor @fd. |
26 | * @fd must be a genuine eventfd object, emulation with pipe won't do. |
27 | */ |
28 | void event_notifier_init_fd(EventNotifier *e, int fd) |
29 | { |
30 | e->rfd = fd; |
31 | e->wfd = fd; |
32 | } |
33 | #endif |
34 | |
35 | int event_notifier_init(EventNotifier *e, int active) |
36 | { |
37 | int fds[2]; |
38 | int ret; |
39 | |
40 | #ifdef CONFIG_EVENTFD |
41 | ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); |
42 | #else |
43 | ret = -1; |
44 | errno = ENOSYS; |
45 | #endif |
46 | if (ret >= 0) { |
47 | e->rfd = e->wfd = ret; |
48 | } else { |
49 | if (errno != ENOSYS) { |
50 | return -errno; |
51 | } |
52 | if (qemu_pipe(fds) < 0) { |
53 | return -errno; |
54 | } |
55 | ret = fcntl_setfl(fds[0], O_NONBLOCK); |
56 | if (ret < 0) { |
57 | ret = -errno; |
58 | goto fail; |
59 | } |
60 | ret = fcntl_setfl(fds[1], O_NONBLOCK); |
61 | if (ret < 0) { |
62 | ret = -errno; |
63 | goto fail; |
64 | } |
65 | e->rfd = fds[0]; |
66 | e->wfd = fds[1]; |
67 | } |
68 | if (active) { |
69 | event_notifier_set(e); |
70 | } |
71 | return 0; |
72 | |
73 | fail: |
74 | close(fds[0]); |
75 | close(fds[1]); |
76 | return ret; |
77 | } |
78 | |
79 | void event_notifier_cleanup(EventNotifier *e) |
80 | { |
81 | if (e->rfd != e->wfd) { |
82 | close(e->rfd); |
83 | e->rfd = -1; |
84 | } |
85 | close(e->wfd); |
86 | e->wfd = -1; |
87 | } |
88 | |
89 | int event_notifier_get_fd(const EventNotifier *e) |
90 | { |
91 | return e->rfd; |
92 | } |
93 | |
94 | int event_notifier_set(EventNotifier *e) |
95 | { |
96 | static const uint64_t value = 1; |
97 | ssize_t ret; |
98 | |
99 | do { |
100 | ret = write(e->wfd, &value, sizeof(value)); |
101 | } while (ret < 0 && errno == EINTR); |
102 | |
103 | /* EAGAIN is fine, a read must be pending. */ |
104 | if (ret < 0 && errno != EAGAIN) { |
105 | return -errno; |
106 | } |
107 | return 0; |
108 | } |
109 | |
110 | int event_notifier_test_and_clear(EventNotifier *e) |
111 | { |
112 | int value; |
113 | ssize_t len; |
114 | char buffer[512]; |
115 | |
116 | /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */ |
117 | value = 0; |
118 | do { |
119 | len = read(e->rfd, buffer, sizeof(buffer)); |
120 | value |= (len > 0); |
121 | } while ((len == -1 && errno == EINTR) || len == sizeof(buffer)); |
122 | |
123 | return value; |
124 | } |
125 | |