int evfilt_socket_copyout(struct kevent *dst, struct knote *src, void *ptr) { struct epoll_event * const ev = (struct epoll_event *) ptr; epoll_event_dump(ev); memcpy(dst, &src->kev, sizeof(*dst)); #if defined(HAVE_EPOLLRDHUP) if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP) dst->flags |= EV_EOF; #else if (ev->events & EPOLLHUP) dst->flags |= EV_EOF; #endif if (ev->events & EPOLLERR) dst->fflags = 1; /* FIXME: Return the actual socket error */ /* On return, data contains the the amount of space remaining in the write buffer */ if (ioctl(dst->ident, SIOCOUTQ, &dst->data) < 0) { /* race condition with socket close, so ignore this error */ dbg_puts("ioctl(2) of socket failed"); dst->data = 0; } return (0); }
static int epoll_update(int op, struct filter *filt, struct knote *kn, struct epoll_event *ev) { dbg_printf("op=%d fd=%d events=%s", op, (int)kn->kev.ident, epoll_event_dump(ev)); if (epoll_ctl(filt->kf_pfd, op, kn->kev.ident, ev) < 0) { dbg_printf("epoll_ctl(2): %s", strerror(errno)); return (-1); } return (0); }
int evfilt_read_copyout(struct kevent *dst, struct knote *src, void *ptr) { struct epoll_event * const ev = (struct epoll_event *) ptr; /* Special case: for regular files, return the offset from current position to end of file */ if (src->kn_flags & KNFL_REGULAR_FILE) { memcpy(dst, &src->kev, sizeof(*dst)); dst->data = get_eof_offset(src->kev.ident); if (dst->data == 0) { dst->filter = 0; /* Will cause the kevent to be discarded */ if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_DEL, src->kdata.kn_eventfd, NULL) < 0) { dbg_perror("epoll_ctl(2)"); return (-1); } #if FIXME /* XXX-FIXME Switch to using kn_inotifyfd to monitor for IN_ATTRIB events that may signify the file size has changed. This code is not tested. */ int inofd; char path[PATH_MAX]; inofd = inotify_init(); if (inofd < 0) { dbg_perror("inotify_init(2)"); (void) close(inofd); return (-1); } src->kdata.kn_inotifyfd = inofd; if (linux_fd_to_path(&path[0], sizeof(path), src->kev.ident) < 0) return (-1); if (inotify_add_watch(inofd, path, IN_ATTRIB) < 0) { dbg_perror("inotify_add_watch"); return (-1); } if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_ADD, src->kdata.kn_inotifyfd, NULL) < 0) { dbg_perror("epoll_ctl(2)"); return (-1); } /* FIXME: race here, should we check the EOF status again ? */ #endif } return (0); } dbg_printf("epoll: %s", epoll_event_dump(ev)); memcpy(dst, &src->kev, sizeof(*dst)); #if defined(HAVE_EPOLLRDHUP) if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP) dst->flags |= EV_EOF; #else if (ev->events & EPOLLHUP) dst->flags |= EV_EOF; #endif if (ev->events & EPOLLERR) dst->fflags = 1; /* FIXME: Return the actual socket error */ if (src->kn_flags & KNFL_PASSIVE_SOCKET) { /* On return, data contains the length of the socket backlog. This is not available under Linux. */ dst->data = 1; } else { /* On return, data contains the number of bytes of protocol data available to read. */ int i; if (ioctl(dst->ident, SIOCINQ, &i) < 0) { /* race condition with socket close, so ignore this error */ dbg_puts("ioctl(2) of socket failed"); dst->data = 0; } else { dst->data = i; if (dst->data == 0) dst->flags |= EV_EOF; } } return (0); }
int evfilt_socket_copyout(struct filter *filt, struct kevent *dst, int nevents) { struct epoll_event epevt[MAX_KEVENT]; struct epoll_event *ev; struct knote *kn; int i, nret; for (;;) { nret = epoll_wait(filt->kf_pfd, &epevt[0], nevents, 0); if (nret < 0) { if (errno == EINTR) continue; dbg_perror("epoll_wait"); return (-1); } else { break; } } for (i = 0, nevents = 0; i < nret; i++) { ev = &epevt[i]; epoll_event_dump(ev); kn = knote_lookup(filt, ev->data.fd); if (kn != NULL) { memcpy(dst, &kn->kev, sizeof(*dst)); #if defined(HAVE_EPOLLRDHUP) if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP) dst->flags |= EV_EOF; #else if (ev->events & EPOLLHUP) dst->flags |= EV_EOF; #endif if (ev->events & EPOLLERR) dst->fflags = 1; /* FIXME: Return the actual socket error */ if (kn->flags & KNFL_PASSIVE_SOCKET) { /* On return, data contains the length of the socket backlog. This is not available under Linux. */ dst->data = 1; } else { /* On return, data contains the number of bytes of protocol data available to read. */ if (ioctl(dst->ident, (dst->filter == EVFILT_READ) ? SIOCINQ : SIOCOUTQ, &dst->data) < 0) { /* race condition with socket close, so ignore this error */ dbg_puts("ioctl(2) of socket failed"); dst->data = 0; } } if (kn->kev.flags & EV_DISPATCH) { socket_knote_delete(filt->kf_pfd, kn->kev.ident); KNOTE_DISABLE(kn); } else if (kn->kev.flags & EV_ONESHOT) { socket_knote_delete(filt->kf_pfd, kn->kev.ident); knote_free(filt, kn); } nevents++; dst++; } } return (nevents); }