ac31e324c529f8c58944a016e27ab6768f5a0a2d
[openvswitch] / lib / poll-loop.c
1 /* Copyright (C) 2008 Board of Trustees, Leland Stanford Jr. University.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21
22 #include "poll-loop.h"
23 #include <assert.h>
24 #include <errno.h>
25 #include <poll.h>
26 #include <string.h>
27 #include "list.h"
28
29 #define THIS_MODULE VLM_poll_loop
30 #include "vlog.h"
31
32 struct poll_waiter {
33     struct list node;
34     int fd;
35     short int events;
36     struct pollfd *pollfd;
37
38     short int *revents;
39
40     poll_fd_func *function;
41     void *aux;
42 };
43
44 static struct list waiters = LIST_INITIALIZER(&waiters);
45 static size_t n_waiters;
46 static int timeout = -1;
47
48 #ifndef NDEBUG
49 static struct poll_waiter *running_cb;
50 #endif
51
52 static struct poll_waiter *
53 new_waiter(int fd, short int events)
54 {
55     struct poll_waiter *waiter = xcalloc(1, sizeof *waiter);
56     assert(fd >= 0);
57     waiter->fd = fd;
58     waiter->events = events;
59     list_push_back(&waiters, &waiter->node);
60     n_waiters++;
61     return waiter;
62 }
63
64 struct poll_waiter *
65 poll_fd_callback(int fd, short int events, poll_fd_func *function, void *aux)
66 {
67     struct poll_waiter *pw = new_waiter(fd, events);
68     pw->function = function;
69     pw->aux = aux;
70     return pw;
71 }
72
73 struct poll_waiter *
74 poll_fd_wait(int fd, short int events, short int *revents)
75 {
76     struct poll_waiter *pw = new_waiter(fd, events);
77     pw->revents = revents;
78     if (revents) {
79         *revents = 0;
80     }
81     return pw;
82 }
83
84 void
85 poll_cancel(struct poll_waiter *pw)
86 {
87     if (pw) {
88         assert(pw != running_cb);
89         list_remove(&pw->node);
90         n_waiters--;
91     }
92 }
93
94 void
95 poll_immediate_wake(void)
96 {
97     timeout = 0;
98 }
99
100 void
101 poll_timer_wait(int msec)
102 {
103     if (timeout < 0 || msec < timeout) {
104         timeout = MAX(0, msec);
105     }
106 }
107
108 void
109 poll_block(void)
110 {
111     static struct pollfd *pollfds;
112     static size_t max_pollfds;
113
114     struct poll_waiter *pw;
115     struct list *node;
116     int n_pollfds;
117     int retval;
118
119     assert(!running_cb);
120     if (max_pollfds < n_waiters) {
121         max_pollfds = n_waiters;
122         pollfds = xrealloc(pollfds, max_pollfds * sizeof *pollfds);
123     }
124
125     n_pollfds = 0;
126     LIST_FOR_EACH (pw, struct poll_waiter, node, &waiters) {
127         pw->pollfd = &pollfds[n_pollfds];
128         pollfds[n_pollfds].fd = pw->fd;
129         pollfds[n_pollfds].events = pw->events;
130         pollfds[n_pollfds].revents = 0;
131         n_pollfds++;
132     }
133
134     do {
135         retval = poll(pollfds, n_pollfds, timeout);
136     } while (retval < 0 && errno == EINTR);
137     if (retval < 0) {
138         VLOG_ERR("poll: %s", strerror(errno));
139     }
140
141     for (node = waiters.next; node != &waiters; ) {
142         pw = CONTAINER_OF(node, struct poll_waiter, node);
143         if (!pw->pollfd || !pw->pollfd->revents) {
144             if (pw->function) {
145                 node = node->next;
146                 continue;
147             }
148         } else {
149             if (pw->function) {
150 #ifndef NDEBUG
151                 running_cb = pw;
152 #endif
153                 pw->function(pw->fd, pw->pollfd->revents, pw->aux);
154 #ifndef NDEBUG
155                 running_cb = NULL;
156 #endif
157             } else if (pw->revents) {
158                 *pw->revents = pw->pollfd->revents;
159             }
160         }
161         node = list_remove(node);
162         n_waiters--;
163     }
164
165     timeout = -1;
166 }