예제 #1
0
파일: signal.c 프로젝트: Breakster/iSoul
/* Callback for when the signal handler write a byte to our signaling socket */
static void
evsig_cb(evutil_socket_t fd, short what, void *arg)
{
	static char signals[1024];
	ev_ssize_t n;
	int i;
	int ncaught[NSIG];
	struct event_base *base;

	base = arg;

	memset(&ncaught, 0, sizeof(ncaught));

	while (1) {
#ifdef _WIN32
		n = recv(fd, signals, sizeof(signals), 0);
#else
		n = read(fd, signals, sizeof(signals));
#endif
		if (n == -1) {
			int err = evutil_socket_geterror(fd);
			if (! EVUTIL_ERR_RW_RETRIABLE(err))
				event_sock_err(1, fd, "%s: recv", __func__);
			break;
		} else if (n == 0) {
			/* XXX warn? */
			break;
		}
		for (i = 0; i < n; ++i) {
			ev_uint8_t sig = signals[i];
			if (sig < NSIG)
				ncaught[sig]++;
		}
	}

	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
	for (i = 0; i < NSIG; ++i) {
		if (ncaught[i])
			evmap_signal_active_(base, i, ncaught[i]);
	}
	EVBASE_RELEASE_LOCK(base, th_base_lock);
}
예제 #2
0
파일: kqueue.c 프로젝트: unix1986/libevent
static int
kq_dispatch(struct event_base *base, struct timeval *tv)
{
    struct kqop *kqop = base->evbase;
    struct kevent *events = kqop->events;
    struct kevent *changes;
    struct timespec ts, *ts_p = NULL;
    int i, n_changes, res;

    if (tv != NULL) {
        TIMEVAL_TO_TIMESPEC(tv, &ts);
        ts_p = &ts;
    }

    /* Build "changes" from "base->changes" */
    EVUTIL_ASSERT(kqop->changes);
    n_changes = kq_build_changes_list(&base->changelist, kqop);
    if (n_changes < 0)
        return -1;

    event_changelist_remove_all_(&base->changelist, base);

    /* steal the changes array in case some broken code tries to call
     * dispatch twice at once. */
    changes = kqop->changes;
    kqop->changes = NULL;

    /* Make sure that 'events' is at least as long as the list of changes:
     * otherwise errors in the changes can get reported as a -1 return
     * value from kevent() rather than as EV_ERROR events in the events
     * array.
     *
     * (We could instead handle -1 return values from kevent() by
     * retrying with a smaller changes array or a larger events array,
     * but this approach seems less risky for now.)
     */
    if (kqop->events_size < n_changes) {
        int new_size = kqop->events_size;
        do {
            new_size *= 2;
        } while (new_size < n_changes);

        kq_grow_events(kqop, new_size);
        events = kqop->events;
    }

    EVBASE_RELEASE_LOCK(base, th_base_lock);

    res = kevent(kqop->kq, changes, n_changes,
                 events, kqop->events_size, ts_p);

    EVBASE_ACQUIRE_LOCK(base, th_base_lock);

    EVUTIL_ASSERT(kqop->changes == NULL);
    kqop->changes = changes;

    if (res == -1) {
        if (errno != EINTR) {
            event_warn("kevent");
            return (-1);
        }

        return (0);
    }

    event_debug(("%s: kevent reports %d", __func__, res));

    for (i = 0; i < res; i++) {
        int which = 0;

        if (events[i].flags & EV_ERROR) {
            switch (events[i].data) {

            /* Can occur on delete if we are not currently
             * watching any events on this fd.  That can
             * happen when the fd was closed and another
             * file was opened with that fd. */
            case ENOENT:
            /* Can occur for reasons not fully understood
             * on FreeBSD. */
            case EINVAL:
                continue;

            /* Can occur on a delete if the fd is closed. */
            case EBADF:
                /* XXXX On NetBSD, we can also get EBADF if we
                 * try to add the write side of a pipe, but
                 * the read side has already been closed.
                 * Other BSDs call this situation 'EPIPE'. It
                 * would be good if we had a way to report
                 * this situation. */
                continue;
            /* These two can occur on an add if the fd was one side
             * of a pipe, and the other side was closed. */
            case EPERM:
            case EPIPE:
                /* Report read events, if we're listening for
                 * them, so that the user can learn about any
                 * add errors.  (If the operation was a
                 * delete, then udata should be cleared.) */
                if (events[i].udata) {
                    /* The operation was an add:
                     * report the error as a read. */
                    which |= EV_READ;
                    break;
                } else {
                    /* The operation was a del:
                     * report nothing. */
                    continue;
                }

            /* Other errors shouldn't occur. */
            default:
                errno = events[i].data;
                return (-1);
            }
        } else if (events[i].filter == EVFILT_READ) {
            which |= EV_READ;
        } else if (events[i].filter == EVFILT_WRITE) {
            which |= EV_WRITE;
        } else if (events[i].filter == EVFILT_SIGNAL) {
            which |= EV_SIGNAL;
#ifdef EVFILT_USER
        } else if (events[i].filter == EVFILT_USER) {
            base->is_notify_pending = 0;
#endif
        }

        if (!which)
            continue;

        if (events[i].filter == EVFILT_SIGNAL) {
            evmap_signal_active_(base, events[i].ident, 1);
        } else {
            evmap_io_active_(base, events[i].ident, which | EV_ET);
        }
    }

    if (res == kqop->events_size) {
        /* We used all the events space that we have. Maybe we should
           make it bigger. */
        kq_grow_events(kqop, kqop->events_size * 2);
    }

    return (0);
}