INT8_MAX,
TEVENT_FD_WRITE,
9,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE);
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR);
}
static void test_event_fd3_readable(struct tevent_context *ev_ctx,
INT8_MAX,
TEVENT_FD_READ|TEVENT_FD_WRITE,
9,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE);
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR);
test_event_fd3_prepare_phase(&state->sock1,
__func__,
7,
TEVENT_FD_READ,
TEVENT_FD_READ|TEVENT_FD_WRITE,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
0,
TEVENT_FD_READ,
TEVENT_FD_WRITE,
- 0,
- TEVENT_FD_READ,
- TEVENT_FD_WRITE,
+ TEVENT_FD_ERROR,
+ TEVENT_FD_WRITE|TEVENT_FD_ERROR,
TEVENT_FD_READ|TEVENT_FD_WRITE);
}
TEVENT_FD_WRITE,
TEVENT_FD_READ,
0,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_WRITE,
- TEVENT_FD_READ,
- 0,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_ERROR,
+ TEVENT_FD_ERROR,
TEVENT_FD_READ);
test_event_fd3_prepare_phase(&state->sock1,
INT8_MAX,
TEVENT_FD_READ,
9,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_READ|TEVENT_FD_WRITE);
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR);
}
static void test_event_fd3_off(struct tevent_context *ev_ctx,
test_event_fd3_prepare_phase(&state->sock1,
__func__,
INT8_MAX,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- 5,
- TEVENT_FD_READ|TEVENT_FD_WRITE,
- TEVENT_FD_WRITE,
- TEVENT_FD_READ,
- 0,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ 7,
TEVENT_FD_READ|TEVENT_FD_WRITE,
TEVENT_FD_WRITE,
TEVENT_FD_READ,
0,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_ERROR,
+ TEVENT_FD_ERROR,
TEVENT_FD_READ);
}
*
* @param[in] fd The file descriptor to base the event on.
*
- * @param[in] flags #TEVENT_FD_READ or #TEVENT_FD_WRITE
+ * @param[in] flags #TEVENT_FD_READ, #TEVENT_FD_WRITE or #TEVENT_FD_ERROR.
*
* @param[in] handler The callback handler for the event.
*
*
* @param[in] fde File descriptor event to query
*
- * @return The flags set on the event. See #TEVENT_FD_READ and
- * #TEVENT_FD_WRITE
+ * @return The flags set on the event. See #TEVENT_FD_READ,
+ * #TEVENT_FD_WRITE and #TEVENT_FD_ERROR
*/
uint16_t tevent_fd_get_flags(struct tevent_fd *fde);
* Set flags on a file descriptor event
*
* @param[in] fde File descriptor event to set
- * @param[in] flags Flags to set on the event. See #TEVENT_FD_READ and
- * #TEVENT_FD_WRITE
+ * @param[in] flags Flags to set on the event. See #TEVENT_FD_READ,
+ * #TEVENT_FD_WRITE and #TEVENT_FD_ERROR
*/
void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
/* bits for file descriptor event flags */
/**
- * Monitor a file descriptor for data to be read
+ * Monitor a file descriptor for data to be read and errors
+ *
+ * Note: we map this from/to POLLIN, POLLHUP, POLLERR and
+ * where available POLLRDHUP
*/
#define TEVENT_FD_READ 1
/**
* Monitor a file descriptor for writeability
+ *
+ * Note: we map this from/to POLLOUT
*/
#define TEVENT_FD_WRITE 2
+/**
+ * Monitor a file descriptor for errors
+ *
+ * Note: we map this from/to POLLHUP, POLLERR and
+ * where available POLLRDHUP
+ */
+#define TEVENT_FD_ERROR 4
/**
* Convenience function for declaring a tevent_fd writable
#define TEVENT_FD_READABLE(fde) \
tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_READ)
+/**
+ * Convenience function for declaring a tevent_fd waiting for errors
+ */
+#define TEVENT_FD_WANTERROR(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_ERROR)
+
/**
* Convenience function for declaring a tevent_fd non-writable
*/
#define TEVENT_FD_NOT_READABLE(fde) \
tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_READ)
+/**
+ * Convenience function for declaring a tevent_fd not waiting for errors
+ */
+#define TEVENT_FD_NOT_WANTERROR(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_ERROR)
+
/**
* Debug level of tevent
*/
static uint32_t epoll_map_flags(uint16_t flags)
{
uint32_t ret = 0;
- if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
- if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
+
+ /*
+ * we do not need to specify EPOLLERR | EPOLLHUP
+ * they are always reported.
+ */
+
+ if (flags & TEVENT_FD_READ) {
+ /*
+ * Note that EPOLLRDHUP always
+ * returns EPOLLIN in addition,
+ * so EPOLLRDHUP is not strictly needed,
+ * but we want to make it explicit.
+ */
+ ret |= EPOLLIN | EPOLLRDHUP;
+ }
+ if (flags & TEVENT_FD_WRITE) {
+ ret |= EPOLLOUT;
+ }
+ if (flags & TEVENT_FD_ERROR) {
+ ret |= EPOLLRDHUP;
+ }
return ret;
}
uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
bool want_read = (effective_flags & TEVENT_FD_READ);
bool want_write= (effective_flags & TEVENT_FD_WRITE);
+ bool want_error= (effective_flags & TEVENT_FD_ERROR);
/* there's already an event */
if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
- if (want_read || (want_write && !got_error)) {
+ if (want_read || want_error || (want_write && !got_error)) {
epoll_mod_event(epoll_ev, primary);
return;
}
}
/* there's no epoll_event attached to the fde */
- if (want_read || (want_write && !got_error)) {
+ if (want_read || want_error || (want_write && !got_error)) {
epoll_add_event(epoll_ev, primary);
return;
}
return -1;
}
effective_flags = tevent_common_fd_mpx_flags(fde);
- if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+ if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP)) {
uint64_t add_flags = 0;
add_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
0,
add_flags);
+ if (effective_flags & TEVENT_FD_ERROR) {
+ flags |= TEVENT_FD_ERROR;
+ }
if (effective_flags & TEVENT_FD_READ) {
flags |= TEVENT_FD_READ;
}
{
snprintf(buf->buf, sizeof(buf->buf),
"%s[fde=%p,"
- "fd=%d,flags=0x%x(%s%s),%s]",
+ "fd=%d,flags=0x%x(%s%s%s),%s]",
description, fde, fde->fd,
fde->flags,
+ (fde->flags & TEVENT_FD_ERROR) ? "E" : "",
(fde->flags & TEVENT_FD_READ) ? "R" : "",
(fde->flags & TEVENT_FD_WRITE) ? "W" : "",
fde->handler_name);
* If we got an error, we won't report it if
* the caller only asked for TEVENT_FD_WRITE.
*/
- if (got_error && !(primary->flags & TEVENT_FD_READ)) {
+ if (got_error &&
+ !(primary->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
+ {
return NULL;
}
* If we got an error, we won't report it if
* the caller only asked for TEVENT_FD_WRITE.
*/
- if (got_error && !(mpx_fde->flags & TEVENT_FD_READ)) {
+ if (got_error &&
+ !(mpx_fde->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
+ {
continue;
}
return fde;
}
+/*
+ map from TEVENT_FD_* to POLLIN/POLLOUT
+*/
+static uint16_t poll_map_flags(uint16_t flags)
+{
+ uint16_t pollflags = 0;
+
+ /*
+ * we do not need to specify POLLERR | POLLHUP
+ * they are always reported.
+ */
+
+ if (flags & TEVENT_FD_READ) {
+ pollflags |= POLLIN;
+#ifdef POLLRDHUP
+ /*
+ * Note that at least on Linux
+ * POLLRDHUP always returns
+ * POLLIN in addition, so this
+ * is not strictly needed, but
+ * we want to make it explicit.
+ */
+ pollflags |= POLLRDHUP;
+#endif
+ }
+ if (flags & TEVENT_FD_WRITE) {
+ pollflags |= POLLOUT;
+ }
+ if (flags & TEVENT_FD_ERROR) {
+#ifdef POLLRDHUP
+ pollflags |= POLLRDHUP;
+#endif
+ }
+
+ return pollflags;
+}
+
/*
set the fd event flags
*/
struct tevent_context *ev = fde->event_ctx;
struct poll_event_context *poll_ev;
uint64_t idx = fde->additional_flags;
- uint16_t pollflags;
if (ev == NULL) {
return;
return;
}
- pollflags = 0;
-
- if (flags & TEVENT_FD_READ) {
- pollflags |= (POLLIN|POLLHUP);
- }
- if (flags & TEVENT_FD_WRITE) {
- pollflags |= (POLLOUT);
- }
- poll_ev->fds[idx].events = pollflags;
+ poll_ev->fds[idx].events = poll_map_flags(flags);
poll_event_wake_pollthread(poll_ev);
}
}
pfd->fd = fde->fd;
- pfd->events = 0;
+ pfd->events = poll_map_flags(fde->flags);
pfd->revents = 0;
- if (fde->flags & TEVENT_FD_READ) {
- pfd->events |= (POLLIN|POLLHUP);
- }
- if (fde->flags & TEVENT_FD_WRITE) {
- pfd->events |= (POLLOUT);
- }
-
poll_ev->num_fds += 1;
}
/* Both are in sync again */
continue;
}
- if (pfd->revents & (POLLHUP|POLLERR)) {
- /* If we only wait for TEVENT_FD_WRITE, we
- should not tell the event handler about it,
- and remove the writable flag, as we only
- report errors when waiting for read events
- to match the select behavior. */
- if (!(fde->flags & TEVENT_FD_READ)) {
+#ifdef POLLRDHUP
+#define __POLL_RETURN_ERROR_FLAGS (POLLHUP|POLLERR|POLLRDHUP)
+#else
+#define __POLL_RETURN_ERROR_FLAGS (POLLHUP|POLLERR)
+#endif
+
+ if (pfd->revents & __POLL_RETURN_ERROR_FLAGS) {
+ /*
+ * If we only wait for TEVENT_FD_WRITE, we
+ * should not tell the event handler about it,
+ * and remove the writable flag, as we only
+ * report errors when waiting for read events
+ * or explicit for errors.
+ */
+ if (!(fde->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
+ {
TEVENT_FD_NOT_WRITEABLE(fde);
continue;
}
- flags |= TEVENT_FD_READ;
+ if (fde->flags & TEVENT_FD_ERROR) {
+ flags |= TEVENT_FD_ERROR;
+ }
+ if (fde->flags & TEVENT_FD_READ) {
+ flags |= TEVENT_FD_READ;
+ }
}
if (pfd->revents & POLLIN) {
flags |= TEVENT_FD_READ;