xref: /openbmc/qemu/util/event_notifier-posix.c (revision a7241974)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * event notifier support
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright Red Hat, Inc. 2010
5baacf047SPaolo Bonzini  *
6baacf047SPaolo Bonzini  * Authors:
7baacf047SPaolo Bonzini  *  Michael S. Tsirkin <mst@redhat.com>
8baacf047SPaolo Bonzini  *
9baacf047SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10baacf047SPaolo Bonzini  * See the COPYING file in the top-level directory.
11baacf047SPaolo Bonzini  */
12baacf047SPaolo Bonzini 
13aafd7584SPeter Maydell #include "qemu/osdep.h"
14f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
15baacf047SPaolo Bonzini #include "qemu/event_notifier.h"
16baacf047SPaolo Bonzini #include "qemu/main-loop.h"
17baacf047SPaolo Bonzini 
18baacf047SPaolo Bonzini #ifdef CONFIG_EVENTFD
19baacf047SPaolo Bonzini #include <sys/eventfd.h>
20baacf047SPaolo Bonzini #endif
21baacf047SPaolo Bonzini 
22330b5836SMarkus Armbruster #ifdef CONFIG_EVENTFD
23330b5836SMarkus Armbruster /*
24330b5836SMarkus Armbruster  * Initialize @e with existing file descriptor @fd.
25330b5836SMarkus Armbruster  * @fd must be a genuine eventfd object, emulation with pipe won't do.
26330b5836SMarkus Armbruster  */
event_notifier_init_fd(EventNotifier * e,int fd)27baacf047SPaolo Bonzini void event_notifier_init_fd(EventNotifier *e, int fd)
28baacf047SPaolo Bonzini {
29baacf047SPaolo Bonzini     e->rfd = fd;
30baacf047SPaolo Bonzini     e->wfd = fd;
31e34e47ebSMaxim Levitsky     e->initialized = true;
32baacf047SPaolo Bonzini }
33330b5836SMarkus Armbruster #endif
34baacf047SPaolo Bonzini 
event_notifier_init(EventNotifier * e,int active)35baacf047SPaolo Bonzini int event_notifier_init(EventNotifier *e, int active)
36baacf047SPaolo Bonzini {
37baacf047SPaolo Bonzini     int fds[2];
38baacf047SPaolo Bonzini     int ret;
39baacf047SPaolo Bonzini 
40baacf047SPaolo Bonzini #ifdef CONFIG_EVENTFD
41baacf047SPaolo Bonzini     ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
42baacf047SPaolo Bonzini #else
43baacf047SPaolo Bonzini     ret = -1;
44baacf047SPaolo Bonzini     errno = ENOSYS;
45baacf047SPaolo Bonzini #endif
46baacf047SPaolo Bonzini     if (ret >= 0) {
47baacf047SPaolo Bonzini         e->rfd = e->wfd = ret;
48baacf047SPaolo Bonzini     } else {
49baacf047SPaolo Bonzini         if (errno != ENOSYS) {
50baacf047SPaolo Bonzini             return -errno;
51baacf047SPaolo Bonzini         }
52*a7241974SMarc-André Lureau         if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) {
53baacf047SPaolo Bonzini             return -errno;
54baacf047SPaolo Bonzini         }
554d14cb0cSMarc-André Lureau         if (!g_unix_set_fd_nonblocking(fds[0], true, NULL)) {
56baacf047SPaolo Bonzini             ret = -errno;
57baacf047SPaolo Bonzini             goto fail;
58baacf047SPaolo Bonzini         }
594d14cb0cSMarc-André Lureau         if (!g_unix_set_fd_nonblocking(fds[1], true, NULL)) {
60baacf047SPaolo Bonzini             ret = -errno;
61baacf047SPaolo Bonzini             goto fail;
62baacf047SPaolo Bonzini         }
63baacf047SPaolo Bonzini         e->rfd = fds[0];
64baacf047SPaolo Bonzini         e->wfd = fds[1];
65baacf047SPaolo Bonzini     }
6682e27568SGreg Kurz     e->initialized = true;
67baacf047SPaolo Bonzini     if (active) {
68baacf047SPaolo Bonzini         event_notifier_set(e);
69baacf047SPaolo Bonzini     }
70baacf047SPaolo Bonzini     return 0;
71baacf047SPaolo Bonzini 
72baacf047SPaolo Bonzini fail:
73baacf047SPaolo Bonzini     close(fds[0]);
74baacf047SPaolo Bonzini     close(fds[1]);
75baacf047SPaolo Bonzini     return ret;
76baacf047SPaolo Bonzini }
77baacf047SPaolo Bonzini 
event_notifier_cleanup(EventNotifier * e)78baacf047SPaolo Bonzini void event_notifier_cleanup(EventNotifier *e)
79baacf047SPaolo Bonzini {
80e34e47ebSMaxim Levitsky     if (!e->initialized) {
81e34e47ebSMaxim Levitsky         return;
82e34e47ebSMaxim Levitsky     }
83e34e47ebSMaxim Levitsky 
84baacf047SPaolo Bonzini     if (e->rfd != e->wfd) {
85baacf047SPaolo Bonzini         close(e->rfd);
86baacf047SPaolo Bonzini     }
87e34e47ebSMaxim Levitsky 
88105e1023SFrediano Ziglio     e->rfd = -1;
89baacf047SPaolo Bonzini     close(e->wfd);
90aa262928SHalil Pasic     e->wfd = -1;
91e34e47ebSMaxim Levitsky     e->initialized = false;
92baacf047SPaolo Bonzini }
93baacf047SPaolo Bonzini 
event_notifier_get_fd(const EventNotifier * e)9412f0b68cSMarc-André Lureau int event_notifier_get_fd(const EventNotifier *e)
95baacf047SPaolo Bonzini {
96baacf047SPaolo Bonzini     return e->rfd;
97baacf047SPaolo Bonzini }
98baacf047SPaolo Bonzini 
event_notifier_get_wfd(const EventNotifier * e)993bcf0fb3SSergio Lopez int event_notifier_get_wfd(const EventNotifier *e)
1003bcf0fb3SSergio Lopez {
1013bcf0fb3SSergio Lopez     return e->wfd;
1023bcf0fb3SSergio Lopez }
1033bcf0fb3SSergio Lopez 
event_notifier_set(EventNotifier * e)104baacf047SPaolo Bonzini int event_notifier_set(EventNotifier *e)
105baacf047SPaolo Bonzini {
106baacf047SPaolo Bonzini     static const uint64_t value = 1;
107baacf047SPaolo Bonzini     ssize_t ret;
108baacf047SPaolo Bonzini 
109e34e47ebSMaxim Levitsky     if (!e->initialized) {
110e34e47ebSMaxim Levitsky         return -1;
111e34e47ebSMaxim Levitsky     }
112e34e47ebSMaxim Levitsky 
113baacf047SPaolo Bonzini     do {
114baacf047SPaolo Bonzini         ret = write(e->wfd, &value, sizeof(value));
115baacf047SPaolo Bonzini     } while (ret < 0 && errno == EINTR);
116baacf047SPaolo Bonzini 
117baacf047SPaolo Bonzini     /* EAGAIN is fine, a read must be pending.  */
118baacf047SPaolo Bonzini     if (ret < 0 && errno != EAGAIN) {
119baacf047SPaolo Bonzini         return -errno;
120baacf047SPaolo Bonzini     }
121baacf047SPaolo Bonzini     return 0;
122baacf047SPaolo Bonzini }
123baacf047SPaolo Bonzini 
event_notifier_test_and_clear(EventNotifier * e)124baacf047SPaolo Bonzini int event_notifier_test_and_clear(EventNotifier *e)
125baacf047SPaolo Bonzini {
126baacf047SPaolo Bonzini     int value;
127baacf047SPaolo Bonzini     ssize_t len;
128baacf047SPaolo Bonzini     char buffer[512];
129baacf047SPaolo Bonzini 
130e34e47ebSMaxim Levitsky     if (!e->initialized) {
131e34e47ebSMaxim Levitsky         return 0;
132e34e47ebSMaxim Levitsky     }
133e34e47ebSMaxim Levitsky 
134baacf047SPaolo Bonzini     /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
135baacf047SPaolo Bonzini     value = 0;
136baacf047SPaolo Bonzini     do {
137baacf047SPaolo Bonzini         len = read(e->rfd, buffer, sizeof(buffer));
138baacf047SPaolo Bonzini         value |= (len > 0);
139baacf047SPaolo Bonzini     } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
140baacf047SPaolo Bonzini 
141baacf047SPaolo Bonzini     return value;
142baacf047SPaolo Bonzini }
143