summaryrefslogtreecommitdiff
path: root/kqueue.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-06-16 13:28:40 -0400
committerNick Mathewson <nickm@torproject.org>2011-06-16 13:28:40 -0400
commit89def5391e3c817f06a7685a0a07cbd33156c108 (patch)
tree15416ec649490b754f6dab693bbb61713c845f62 /kqueue.c
parent33124033fd650a603d64e91151c8faa96adc3f98 (diff)
parent79ff78d2e7d48ca32df5f0dee10ec932d2812108 (diff)
downloadlibevent-89def5391e3c817f06a7685a0a07cbd33156c108.tar.gz
Merge remote-tracking branch 'origin/patches-2.0'
Diffstat (limited to 'kqueue.c')
-rw-r--r--kqueue.c65
1 files changed, 46 insertions, 19 deletions
diff --git a/kqueue.c b/kqueue.c
index bf5a1c9d..b0772dc1 100644
--- a/kqueue.c
+++ b/kqueue.c
@@ -50,8 +50,10 @@
* easy way to tell them apart via autoconf, so we need to use OS macros. */
#if defined(_EVENT_HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
#define PTR_TO_UDATA(x) ((intptr_t)(x))
+#define INT_TO_UDATA(x) ((intptr_t)(x))
#else
#define PTR_TO_UDATA(x) (x)
+#define INT_TO_UDATA(x) ((void*)(x))
#endif
#include "event-internal.h"
@@ -168,6 +170,8 @@ kq_sighandler(int sig)
/* Do nothing here */
}
+#define ADD_UDATA 0x30303
+
static void
kq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change)
{
@@ -177,6 +181,9 @@ kq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change
if (change & EV_CHANGE_ADD) {
out->flags = EV_ADD;
+ /* We set a magic number here so that we can tell 'add'
+ * errors from 'del' errors. */
+ out->udata = INT_TO_UDATA(ADD_UDATA);
if (change & EV_ET)
out->flags |= EV_CLEAR;
#ifdef NOTE_EOF
@@ -315,27 +322,47 @@ kq_dispatch(struct event_base *base, struct timeval *tv)
int which = 0;
if (events[i].flags & EV_ERROR) {
- /*
- * Error messages that can happen, when a delete fails.
- * EBADF happens when the file descriptor has been
- * closed,
- * ENOENT when the file descriptor was closed and
- * then reopened.
- * EINVAL for some reasons not understood; EINVAL
- * should not be returned ever; but FreeBSD does :-\
- * An error is also indicated when a callback deletes
- * an event we are still processing. In that case
- * the data field is set to ENOENT.
- */
- if (events[i].data == EBADF ||
- events[i].data == EINVAL ||
- events[i].data == ENOENT)
+ 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;
- errno = events[i].data;
- return (-1);
- }
- if (events[i].filter == EVFILT_READ) {
+ /* Can occur on a delete if the fd is closed. Can
+ * occur on an add if the fd was one side of a pipe,
+ * and the other side was closed. */
+ case EBADF:
+ /* 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;