2 * Copyright (c) 2013-2015 Todd C. Miller <Todd.Miller@sudo.ws>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
19 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
24 #include <sys/types.h>
30 # include "compat/stdbool.h"
31 #endif /* HAVE_STDBOOL_H */
34 #endif /* HAVE_STRING_H */
37 #endif /* HAVE_STRINGS_H */
43 #include "sudo_compat.h"
44 #include "sudo_util.h"
45 #include "sudo_fatal.h"
46 #include "sudo_debug.h"
47 #include "sudo_event.h"
50 sudo_ev_base_alloc_impl(struct sudo_event_base *base)
53 debug_decl(sudo_ev_base_alloc_impl, SUDO_DEBUG_EVENT)
57 base->pfds = reallocarray(NULL, base->pfd_max, sizeof(struct pollfd));
58 if (base->pfds == NULL) {
59 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
60 "%s: unable to allocate %d pollfds", __func__, base->pfd_max);
64 for (i = 0; i < base->pfd_max; i++) {
65 base->pfds[i].fd = -1;
72 sudo_ev_base_free_impl(struct sudo_event_base *base)
74 debug_decl(sudo_ev_base_free_impl, SUDO_DEBUG_EVENT)
80 sudo_ev_add_impl(struct sudo_event_base *base, struct sudo_event *ev)
83 debug_decl(sudo_ev_add_impl, SUDO_DEBUG_EVENT)
85 /* If out of space in pfds array, realloc. */
86 if (base->pfd_free == base->pfd_max) {
91 reallocarray(base->pfds, base->pfd_max, 2 * sizeof(struct pollfd));
93 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
94 "%s: unable to allocate %d pollfds", __func__, base->pfd_max * 2);
99 for (i = base->pfd_free; i < base->pfd_max; i++) {
100 base->pfds[i].fd = -1;
104 /* Fill in pfd entry. */
105 ev->pfd_idx = base->pfd_free;
106 pfd = &base->pfds[ev->pfd_idx];
109 if (ISSET(ev->events, SUDO_EV_READ))
110 pfd->events |= POLLIN;
111 if (ISSET(ev->events, SUDO_EV_WRITE))
112 pfd->events |= POLLOUT;
114 /* Update pfd_high and pfd_free. */
115 if (ev->pfd_idx > base->pfd_high)
116 base->pfd_high = ev->pfd_idx;
118 if (++base->pfd_free == base->pfd_max)
120 if (base->pfds[base->pfd_free].fd == -1)
128 sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev)
130 debug_decl(sudo_ev_del_impl, SUDO_DEBUG_EVENT)
132 /* Mark pfd entry unused, add to free list and adjust high slot. */
133 base->pfds[ev->pfd_idx].fd = -1;
134 if (ev->pfd_idx < base->pfd_free)
135 base->pfd_free = ev->pfd_idx;
136 while (base->pfd_high >= 0 && base->pfds[base->pfd_high].fd == -1)
144 sudo_ev_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timo)
146 return ppoll(fds, nfds, timo, NULL);
150 sudo_ev_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timo)
153 timo ? (timo->tv_sec * 1000) + (timo->tv_nsec / 1000000) : -1;
155 return poll(fds, nfds, timeout);
157 #endif /* HAVE_PPOLL */
160 sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
162 struct timespec now, ts, *timeout;
163 struct sudo_event *ev;
165 debug_decl(sudo_ev_scan_impl, SUDO_DEBUG_EVENT)
167 if ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
168 sudo_gettime_mono(&now);
169 sudo_timespecsub(&ev->timeout, &now, &ts);
171 sudo_timespecclear(&ts);
174 if (ISSET(flags, SUDO_EVLOOP_NONBLOCK)) {
175 sudo_timespecclear(&ts);
182 nready = sudo_ev_poll(base->pfds, base->pfd_high + 1, timeout);
183 sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %d fds ready", __func__, nready);
186 /* Error or interrupted by signal. */
187 debug_return_int(-1);
189 /* Front end will activate timeout events. */
192 /* Activate each I/O event that fired. */
193 TAILQ_FOREACH(ev, &base->events, entries) {
194 if (ev->pfd_idx != -1 && base->pfds[ev->pfd_idx].revents) {
196 if (base->pfds[ev->pfd_idx].revents & (POLLIN|POLLHUP|POLLNVAL|POLLERR))
197 what |= (ev->events & SUDO_EV_READ);
198 if (base->pfds[ev->pfd_idx].revents & (POLLOUT|POLLHUP|POLLNVAL|POLLERR))
199 what |= (ev->events & SUDO_EV_WRITE);
200 /* Make event active. */
201 sudo_debug_printf(SUDO_DEBUG_DEBUG,
202 "%s: polled fd %d, events %d, activating %p",
203 __func__, ev->fd, what, ev);
205 sudo_ev_activate(base, ev);
210 debug_return_int(nready);