1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/*
2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon
3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * All rights reserved
5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without
7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions
8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met:
9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright
10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer.
11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright
12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer in the
13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    documentation and/or other materials provided with the distribution.
14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *
15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE.
26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */
27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/time.h>
29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h>
31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <limits.h>
32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <signal.h>
33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h>
34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h>
35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h>
36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h"
38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h"
39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcpcd.h"
40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "eloop.h"
41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/event.h>
44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h>
45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef __NetBSD__
46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* udata is void * except on NetBSD
47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * lengths are int except on NetBSD */
48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define UPTR(x)	((intptr_t)(x))
49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define LENC(x)	(x)
50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define UPTR(x)	(x)
52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define LENC(x)	((int)(x))
53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define eloop_event_setup_fds(ctx)
55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/epoll.h>
57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define eloop_event_setup_fds(ctx)
58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <poll.h>
60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_event_setup_fds(struct eloop_ctx *ctx)
62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_event *e;
64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	i = 0;
67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(e, &ctx->events, next) {
68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->fds[i].fd = e->fd;
69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->fds[i].events = 0;
70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->read_cb)
71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ctx->fds[i].events |= POLLIN;
72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->write_cb)
73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ctx->fds[i].events |= POLLOUT;
74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->fds[i].revents = 0;
75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e->pollfd = &ctx->fds[i];
76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		i++;
77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_event_add(struct eloop_ctx *ctx, int fd,
83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void (*read_cb)(void *), void *read_cb_arg,
84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void (*write_cb)(void *), void *write_cb_arg)
85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_event *e;
87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct kevent ke[2];
89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct epoll_event epe;
91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct pollfd *nfds;
93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef HAVE_EPOLL
96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&epe, 0, sizeof(epe));
97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	epe.data.fd = fd;
98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	epe.events = EPOLLIN;
99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (write_cb)
100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		epe.events |= EPOLLOUT;
101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We should only have one callback monitoring the fd */
104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(e, &ctx->events, next) {
105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->fd == fd) {
106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			int error;
107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD,
110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    0, 0, UPTR(e));
111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (write_cb)
112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    EV_ADD, 0, 0, UPTR(e));
114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else if (e->write_cb)
115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    EV_DELETE, 0, 0, UPTR(e));
117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			error = kevent(ctx->poll_fd, ke,
118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    e->write_cb || write_cb ? 2 : 1, NULL, 0, NULL);
119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			epe.data.ptr = e;
121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			error = epoll_ctl(ctx->poll_fd, EPOLL_CTL_MOD,
122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    fd, &epe);
123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			error = 0;
125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (read_cb) {
127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->read_cb = read_cb;
128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->read_cb_arg = read_cb_arg;
129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (write_cb) {
131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->write_cb = write_cb;
132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->write_cb_arg = write_cb_arg;
133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_event_setup_fds(ctx);
135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return error;
136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Allocate a new event if no free ones already allocated */
140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((e = TAILQ_FIRST(&ctx->free_events))) {
141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&ctx->free_events, e, next);
142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = malloc(sizeof(*e));
144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e == NULL)
145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto err;
146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Ensure we can actually listen to it */
149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->events_len++;
150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->events_len > ctx->fds_len) {
152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nfds = realloc(ctx->fds, sizeof(*ctx->fds) * (ctx->fds_len+5));
153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (nfds == NULL)
154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto err;
155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->fds_len += 5;
156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->fds = nfds;
157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Now populate the structure and add it to the list */
161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e->fd = fd;
162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e->read_cb = read_cb;
163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e->read_cb_arg = read_cb_arg;
164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e->write_cb = write_cb;
165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e->write_cb_arg = write_cb_arg;
166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, UPTR(e));
169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (write_cb)
170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    EV_ADD, 0, 0, UPTR(e));
172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (kevent(ctx->poll_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1)
173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto err;
174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	epe.data.ptr = e;
176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (epoll_ctl(ctx->poll_fd, EPOLL_CTL_ADD, fd, &epe) == -1)
177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto err;
178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* The order of events should not matter.
181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * However, some PPP servers love to close the link right after
182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * sending their final message. So to ensure dhcpcd processes this
183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * message (which is likely to be that the DHCP addresses are wrong)
184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * we insert new events at the queue head as the link fd will be
185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * the first event added. */
186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INSERT_HEAD(&ctx->events, e, next);
187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_event_setup_fds(ctx);
188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanerr:
191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ctx->ctx, LOG_ERR, "%s: %m", __func__);
192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (e) {
193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->events_len--;
194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_event_delete(struct eloop_ctx *ctx, int fd, int write_only)
201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_event *e;
203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct kevent ke[2];
205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct epoll_event epe;
207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(e, &ctx->events, next) {
210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->fd == fd) {
211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (write_only) {
212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (e->write_cb) {
213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					e->write_cb = NULL;
214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					e->write_cb_arg = NULL;
215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					EV_SET(&ke[0], (uintptr_t)fd,
217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    EVFILT_WRITE, EV_DELETE,
218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    0, 0, UPTR(NULL));
219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					kevent(ctx->poll_fd, ke, 1, NULL, 0,
220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    NULL);
221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					memset(&epe, 0, sizeof(epe));
223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					epe.data.fd = e->fd;
224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					epe.data.ptr = e;
225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					epe.events = EPOLLIN;
226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					epoll_ctl(ctx->poll_fd, EPOLL_CTL_MOD,
227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    fd, &epe);
228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else {
232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				TAILQ_REMOVE(&ctx->events, e, next);
233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    EV_DELETE, 0, 0, UPTR(NULL));
236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (e->write_cb)
237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					EV_SET(&ke[1], (uintptr_t)fd,
238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    EVFILT_WRITE, EV_DELETE,
239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    0, 0, UPTR(NULL));
240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				kevent(ctx->poll_fd, ke, e->write_cb ? 2 : 1,
241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    NULL, 0, NULL);
242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* NULL event is safe because we
244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * rely on epoll_pwait which as added
245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * after the delete without event was fixed. */
246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				epoll_ctl(ctx->poll_fd, EPOLL_CTL_DEL,
247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    fd, NULL);
248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ctx->events_len--;
251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_event_setup_fds(ctx);
253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct timespec *when, void (*callback)(void *), void *arg)
261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec now, w;
263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_timeout *t, *tt = NULL;
264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	get_monotonic(&now);
266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	timespecadd(&now, when, &w);
267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Check for time_t overflow. */
268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (timespeccmp(&w, &now, <)) {
269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ERANGE;
270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Remove existing timeout if present */
274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(t, &ctx->timeouts, next) {
275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (t->callback == callback && t->arg == arg) {
276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_REMOVE(&ctx->timeouts, t, next);
277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (t == NULL) {
282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* No existing, so allocate or grab one from the free pool */
283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_REMOVE(&ctx->free_timeouts, t, next);
285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			t = malloc(sizeof(*t));
287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (t == NULL) {
288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ctx->ctx, LOG_ERR, "%s: %m", __func__);
289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return -1;
290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	t->when = w;
295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	t->callback = callback;
296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	t->arg = arg;
297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	t->queue = queue;
298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* The timeout list should be in chronological order,
300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * soonest first. */
301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(tt, &ctx->timeouts, next) {
302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (timespeccmp(&t->when, &tt->when, <)) {
303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_INSERT_BEFORE(tt, t, next);
304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 0;
305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INSERT_TAIL(&ctx->timeouts, t, next);
308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_q_timeout_add_sec(struct eloop_ctx *ctx, int queue, time_t when,
313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void (*callback)(void *), void *arg)
314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec tv;
316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	tv.tv_sec = when;
318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	tv.tv_nsec = 0;
319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if !defined(HAVE_KQUEUE)
323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_timeout_add_now(struct eloop_ctx *ctx,
325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void (*callback)(void *), void *arg)
326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->timeout0 != NULL) {
329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx->ctx, LOG_WARNING,
330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: timeout0 already set", __func__);
331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return eloop_q_timeout_add_sec(ctx, 0, 0, callback, arg);
332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->timeout0 = callback;
335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->timeout0_arg = arg;
336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_q_timeout_delete(struct eloop_ctx *ctx, int queue,
342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void (*callback)(void *), void *arg)
343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_timeout *t, *tt;
345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH_SAFE(t, &ctx->timeouts, next, tt) {
347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((queue == 0 || t->queue == queue) &&
348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    t->arg == arg &&
349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (!callback || t->callback == callback))
350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_REMOVE(&ctx->timeouts, t, next);
352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_exit(struct eloop_ctx *ctx, int code)
359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->exitcode = code;
362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx->exitnow = 1;
363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_open(struct eloop_ctx *ctx)
368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE1)
370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (ctx->poll_fd = kqueue1(O_CLOEXEC));
371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_KQUEUE)
372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int i;
373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((ctx->poll_fd = kqueue()) == -1)
375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((i = fcntl(ctx->poll_fd, F_GETFD, 0)) == -1 ||
377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(ctx->poll_fd, F_SETFD, i | FD_CLOEXEC) == -1)
378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(ctx->poll_fd);
380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->poll_fd = -1;
381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx->poll_fd;
385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined (HAVE_EPOLL)
386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (ctx->poll_fd = epoll_create1(EPOLL_CLOEXEC));
387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_requeue(struct eloop_ctx *ctx)
392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_event *e;
394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int error;
395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct kevent *ke;
398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct epoll_event epe;
400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->poll_fd != -1)
403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(ctx->poll_fd);
404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (eloop_open(ctx) == -1)
405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined (HAVE_KQUEUE)
407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	i = 0;
408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (dhcpcd_handlesigs[i])
409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		i++;
410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(e, &ctx->events, next) {
411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		i++;
412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->write_cb)
413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			i++;
414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((ke = malloc(sizeof(*ke) * i)) == NULL)
417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0; dhcpcd_handlesigs[i]; i++)
420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		EV_SET(&ke[i], (uintptr_t)dhcpcd_handlesigs[i],
421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL));
422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(e, &ctx->events, next) {
424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_READ,
425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    EV_ADD, 0, 0, UPTR(e));
426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		i++;
427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->write_cb) {
428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_WRITE,
429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    EV_ADD, 0, 0, UPTR(e));
430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			i++;
431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	error =  kevent(ctx->poll_fd, ke, LENC(i), NULL, 0, NULL);
435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(ke);
436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	error = 0;
440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(e, &ctx->events, next) {
441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memset(&epe, 0, sizeof(epe));
442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		epe.data.fd = e->fd;
443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		epe.events = EPOLLIN;
444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (e->write_cb)
445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			epe.events |= EPOLLOUT;
446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		epe.data.ptr = e;
447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (epoll_ctl(ctx->poll_fd, EPOLL_CTL_ADD, e->fd, &epe) == -1)
448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			error = -1;
449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return error;
453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct eloop_ctx *
457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_init(struct dhcpcd_ctx *dctx)
458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_ctx *ctx;
460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec now;
461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Check we have a working monotonic clock. */
463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_monotonic(&now) == -1)
464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx = calloc(1, sizeof(*ctx));
467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx) {
468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->ctx = dctx;
469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&ctx->events);
470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&ctx->free_events);
471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&ctx->timeouts);
472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&ctx->free_timeouts);
473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->exitcode = EXIT_FAILURE;
474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->poll_fd = -1;
476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (eloop_requeue(ctx) == -1) {
478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(ctx);
479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx;
484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid eloop_free(struct eloop_ctx *ctx)
487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_event *e;
489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_timeout *t;
490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx == NULL)
492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((e = TAILQ_FIRST(&ctx->events))) {
495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&ctx->events, e, next);
496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(e);
497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((e = TAILQ_FIRST(&ctx->free_events))) {
499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&ctx->free_events, e, next);
500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(e);
501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((t = TAILQ_FIRST(&ctx->timeouts))) {
503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&ctx->timeouts, t, next);
504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(t);
505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_REMOVE(&ctx->free_timeouts, t, next);
508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(t);
509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(ctx->poll_fd);
512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(ctx->fds);
514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(ctx);
516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneloop_start(struct eloop_ctx *ctx)
520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int n;
522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_event *e;
523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct eloop_timeout *t;
524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec now, ts, *tsp;
525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	void (*t0)(void *);
526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int timeout;
528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct kevent ke;
531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct epoll_event epe;
533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (;;) {
536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ctx->exitnow)
537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Run all timeouts first */
540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ctx->timeout0) {
541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			t0 = ctx->timeout0;
542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ctx->timeout0 = NULL;
543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			t0(ctx->timeout0_arg);
544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((t = TAILQ_FIRST(&ctx->timeouts))) {
547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			get_monotonic(&now);
548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (timespeccmp(&now, &t->when, >)) {
549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				TAILQ_REMOVE(&ctx->timeouts, t, next);
550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				t->callback(t->arg);
551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			timespecsub(&t->when, &now, &ts);
555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			tsp = &ts;
556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else
557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* No timeouts, so wait forever */
558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			tsp = NULL;
559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (tsp == NULL && ctx->events_len == 0) {
561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx->ctx, LOG_ERR, "nothing to do");
562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (tsp == NULL)
567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			timeout = -1;
568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (tsp->tv_sec > INT_MAX / 1000 ||
569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (tsp->tv_sec == INT_MAX / 1000 &&
570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (tsp->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			timeout = INT_MAX;
572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			timeout = (int)(tsp->tv_sec * 1000 +
574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (tsp->tv_nsec + 999999) / 1000000);
575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n = kevent(ctx->poll_fd, NULL, 0, &ke, 1, tsp);
579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef USE_SIGNALS
581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n = epoll_pwait(ctx->poll_fd, &epe, 1, timeout,
582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &ctx->ctx->sigset);
583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n = epoll_wait(ctx->poll_fd, &epe, 1, timeout);
585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef USE_SIGNALS
588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n = pollts(ctx->fds, (nfds_t)ctx->events_len, tsp,
589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &ctx->ctx->sigset);
590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n = poll(ctx->fds, (nfds_t)ctx->events_len, timeout);
592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (n == -1) {
595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (errno == EINTR)
596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx->ctx, LOG_ERR, "poll: %m");
598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Process any triggered events.
602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * We go back to the start after calling each callback incase
603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * the current event or next event is removed. */
604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(HAVE_KQUEUE)
605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (n) {
606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (ke.filter == EVFILT_SIGNAL) {
607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				struct dhcpcd_siginfo si;
608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				si.signo = (int)ke.ident;
610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				dhcpcd_handle_signal(&si);
611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e = (struct eloop_event *)ke.udata;
614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (ke.filter == EVFILT_WRITE) {
615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->write_cb(e->write_cb_arg);
616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else if (ke.filter == EVFILT_READ) {
618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->read_cb(e->read_cb_arg);
619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(HAVE_EPOLL)
623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (n) {
624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e = (struct eloop_event *)epe.data.ptr;
625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (epe.events & EPOLLOUT && e->write_cb) {
626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->write_cb(e->write_cb_arg);
627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (epe.events &
630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (EPOLLIN | EPOLLERR | EPOLLHUP))
631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e->read_cb(e->read_cb_arg);
633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (n > 0) {
638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_FOREACH(e, &ctx->events, next) {
639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (e->pollfd->revents & POLLOUT &&
640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    e->write_cb)
641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				{
642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					e->write_cb(e->write_cb_arg);
643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					break;
644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (e->pollfd->revents) {
646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					e->read_cb(e->read_cb_arg);
647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					break;
648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ctx->exitcode;
655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
656