Annotation of embedaddon/sudo/common/event_select.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 2013 Todd C. Miller <Todd.Miller@courtesan.com>
                      3:  *
                      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.
                      7:  *
                      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.
                     15:  */
                     16: 
                     17: #include <config.h>
                     18: 
                     19: #include <sys/param.h>         /* for howmany() on Linux */
                     20: #include <sys/time.h>
                     21: #ifdef HAVE_SYS_SYSMACROS_H
                     22: # include <sys/sysmacros.h>    /* for howmany() on Solaris */
                     23: #endif
                     24: #ifdef HAVE_SYS_SELECT_H
                     25: # include <sys/select.h>
                     26: #endif /* HAVE_SYS_SELECT_H */
                     27: #include <stdio.h>
                     28: #ifdef STDC_HEADERS
                     29: # include <stdlib.h>
                     30: # include <stddef.h>
                     31: #else
                     32: # ifdef HAVE_STDLIB_H
                     33: #  include <stdlib.h>
                     34: # endif
                     35: #endif /* STDC_HEADERS */
                     36: #ifdef HAVE_STDBOOL_H
                     37: # include <stdbool.h>
                     38: #else
                     39: # include "compat/stdbool.h"
                     40: #endif /* HAVE_STDBOOL_H */
                     41: #ifdef HAVE_STRING_H
                     42: # include <string.h>
                     43: #endif /* HAVE_STRING_H */
                     44: #ifdef HAVE_STRINGS_H
                     45: # include <strings.h>
                     46: #endif /* HAVE_STRINGS_H */
                     47: #ifdef HAVE_UNISTD_H
                     48: # include <unistd.h>
                     49: #endif /* HAVE_UNISTD_H */
                     50: #include <errno.h>
                     51: 
                     52: #include "missing.h"
                     53: #include "alloc.h"
                     54: #include "fatal.h"
                     55: #include "sudo_debug.h"
                     56: #include "sudo_event.h"
                     57: #include "sudo_util.h"
                     58: 
                     59: /* XXX - use non-exiting allocators? */
                     60: 
                     61: int
                     62: sudo_ev_base_alloc_impl(struct sudo_event_base *base)
                     63: {
                     64:     debug_decl(sudo_ev_base_alloc_impl, SUDO_DEBUG_EVENT)
                     65: 
                     66:     base->maxfd = NFDBITS - 1;
                     67:     base->readfds_in = ecalloc(1, sizeof(fd_mask));
                     68:     base->writefds_in = ecalloc(1, sizeof(fd_mask));
                     69:     base->readfds_out = ecalloc(1, sizeof(fd_mask));
                     70:     base->writefds_out = ecalloc(1, sizeof(fd_mask));
                     71: 
                     72:     debug_return_int(0);
                     73: }
                     74: 
                     75: void
                     76: sudo_ev_base_free_impl(struct sudo_event_base *base)
                     77: {
                     78:     debug_decl(sudo_ev_base_free_impl, SUDO_DEBUG_EVENT)
                     79:     efree(base->readfds_in);
                     80:     efree(base->writefds_in);
                     81:     efree(base->readfds_out);
                     82:     efree(base->writefds_out);
                     83:     debug_return;
                     84: }
                     85: 
                     86: int
                     87: sudo_ev_add_impl(struct sudo_event_base *base, struct sudo_event *ev)
                     88: {
                     89:     debug_decl(sudo_ev_add_impl, SUDO_DEBUG_EVENT)
                     90: 
                     91:     /* If out of space in fd sets, realloc. */
                     92:     if (ev->fd > base->maxfd) {
                     93:        const int o = (base->maxfd + 1) / NFDBITS;
                     94:        const int n = howmany(ev->fd + 1, NFDBITS);
                     95:        base->readfds_in = erecalloc(base->readfds_in, o, n, sizeof(fd_mask));
                     96:        base->writefds_in = erecalloc(base->writefds_in, o, n, sizeof(fd_mask));
                     97:        base->readfds_out = erecalloc(base->readfds_out, o, n, sizeof(fd_mask));
                     98:        base->writefds_out = erecalloc(base->writefds_out, o, n, sizeof(fd_mask));
                     99:        base->maxfd = (n * NFDBITS) - 1;
                    100:     }
                    101: 
                    102:     /* Set events and adjust high fd as needed. */
                    103:     if (ISSET(ev->events, SUDO_EV_READ)) {
                    104:        sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: added fd %d to readfs",
                    105:            __func__, ev->fd);
                    106:        FD_SET(ev->fd, base->readfds_in);
                    107:     }
                    108:     if (ISSET(ev->events, SUDO_EV_WRITE)) {
                    109:        sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: added fd %d to writefds",
                    110:            __func__, ev->fd);
                    111:        FD_SET(ev->fd, base->writefds_in);
                    112:     }
                    113:     if (ev->fd > base->highfd)
                    114:        base->highfd = ev->fd;
                    115: 
                    116:     debug_return_int(0);
                    117: }
                    118: 
                    119: int
                    120: sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev)
                    121: {
                    122:     debug_decl(sudo_ev_del_impl, SUDO_DEBUG_EVENT)
                    123: 
                    124:     /* Remove from readfds and writefds and adjust high fd. */
                    125:     if (ISSET(ev->events, SUDO_EV_READ)) {
                    126:        sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: removed fd %d from readfds",
                    127:            __func__, ev->fd);
                    128:        FD_CLR(ev->fd, base->readfds_in);
                    129:     }
                    130:     if (ISSET(ev->events, SUDO_EV_WRITE)) {
                    131:        sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: removed fd %d from writefds",
                    132:            __func__, ev->fd);
                    133:        FD_CLR(ev->fd, base->writefds_in);
                    134:     }
                    135:     if (base->highfd == ev->fd) {
                    136:        for (;;) {
                    137:            if (FD_ISSET(base->highfd, base->readfds_in) ||
                    138:                FD_ISSET(base->highfd, base->writefds_in))
                    139:                break;
                    140:            if (--base->highfd < 0)
                    141:                break;
                    142:        }
                    143:     }
                    144: 
                    145:     debug_return_int(0);
                    146: }
                    147: 
                    148: int
                    149: sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
                    150: {
                    151:     struct timeval now, tv, *timeout;
                    152:     struct sudo_event *ev;
                    153:     size_t setsize;
                    154:     int nready;
                    155:     debug_decl(sudo_ev_loop, SUDO_DEBUG_EVENT)
                    156: 
                    157:     if ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
                    158:        gettimeofday(&now, NULL);
                    159:        sudo_timevalsub(&ev->timeout, &now, &tv);
                    160:        if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec < 0))
                    161:            sudo_timevalclear(&tv);
                    162:        timeout = &tv;
                    163:     } else {
                    164:        if (ISSET(flags, SUDO_EVLOOP_NONBLOCK)) {
                    165:            sudo_timevalclear(&tv);
                    166:            timeout = &tv;
                    167:        } else {
                    168:            timeout = NULL;
                    169:        }
                    170:     }
                    171: 
                    172:     /* select() overwrites readfds/writefds so make a copy. */
                    173:     setsize = howmany(base->highfd + 1, NFDBITS) * sizeof(fd_mask);
                    174:     memcpy(base->readfds_out, base->readfds_in, setsize);
                    175:     memcpy(base->writefds_out, base->writefds_in, setsize);
                    176: 
                    177:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: select high fd %d",
                    178:        __func__, base->highfd);
                    179:     nready = select(base->highfd + 1, base->readfds_out, base->writefds_out,
                    180:        NULL, timeout);
                    181:     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %d fds ready", __func__, nready);
                    182:     switch (nready) {
                    183:     case -1:
                    184:        /* Error or interrupted by signal. */
                    185:        debug_return_int(-1);
                    186:     case 0:
                    187:        /* Front end will activate timeout events. */
                    188:        break;
                    189:     default:
                    190:        /* Activate each I/O event that fired. */
                    191:        TAILQ_FOREACH(ev, &base->events, entries) {
                    192:            if (ev->fd >= 0) {
                    193:                int what = 0;
                    194:                if (FD_ISSET(ev->fd, base->readfds_out))
                    195:                    what |= (ev->events & SUDO_EV_READ);
                    196:                if (FD_ISSET(ev->fd, base->writefds_out))
                    197:                    what |= (ev->events & SUDO_EV_WRITE);
                    198:                if (what != 0) {
                    199:                    /* Make event active. */
                    200:                    sudo_debug_printf(SUDO_DEBUG_DEBUG,
                    201:                        "%s: selected fd %d, events %d, activating %p",
                    202:                        __func__, ev->fd, what, ev);
                    203:                    ev->revents = what;
                    204:                    TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
                    205:                    SET(ev->flags, SUDO_EVQ_ACTIVE);
                    206:                }
                    207:            }
                    208:        }
                    209:        break;
                    210:     }
                    211:     debug_return_int(nready);
                    212: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>