Index: sys/compat/linux/linux_event.c =================================================================== --- sys/compat/linux/linux_event.c +++ sys/compat/linux/linux_event.c @@ -219,18 +219,22 @@ if ((levents & LINUX_EPOLL_EVRD) != 0) { EV_SET(kevent, fd, EVFILT_READ, kev_flags, 0, 0, 0); kevent->ext[0] = l_event->data; + kevent->pmask = levents; ++kevent; ++(*nkevents); } if ((levents & LINUX_EPOLL_EVWR) != 0) { EV_SET(kevent, fd, EVFILT_WRITE, kev_flags, 0, 0, 0); kevent->ext[0] = l_event->data; + kevent->pmask = levents; ++kevent; ++(*nkevents); } /* zero event mask is legal */ if ((levents & (LINUX_EPOLL_EVRD | LINUX_EPOLL_EVWR)) == 0) { - EV_SET(kevent++, fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, 0); + EV_SET(kevent, fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, 0); + kevent->pmask = levents; + ++kevent; ++(*nkevents); } @@ -262,12 +266,10 @@ static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event) { - l_event->data = kevent->ext[0]; if ((kevent->flags & EV_ERROR) != 0) { l_event->events = LINUX_EPOLLERR; - return; } /* XXX EPOLLPRI, EPOLLHUP */ @@ -281,6 +283,37 @@ l_event->events = LINUX_EPOLLOUT; break; } + + /* Handle all events to meet all Linux epoll cases */ + if ((kevent->pevents & EV_POLLIN) != 0) { + l_event->events |= LINUX_EPOLLIN; + } + if ((kevent->pevents & EV_POLLHUP) != 0) { + l_event->events |= LINUX_EPOLLHUP; + } + if ((kevent->pevents & EV_POLLRDHUP) != 0) { + l_event->events |= LINUX_EPOLLRDHUP; + } + if ((kevent->pevents & EV_POLLRDNORM) != 0) { + l_event->events |= LINUX_EPOLLRDNORM; + } + if ((kevent->pevents & EV_POLLERR) != 0) { + l_event->events |= LINUX_EPOLLERR; + } + if ((kevent->pevents & EV_POLLOUT) != 0) { + l_event->events |= LINUX_EPOLLOUT; + } + if ((kevent->pevents & EV_POLLWRNORM) != 0) { + l_event->events |= LINUX_EPOLLWRNORM; + } + if ((kevent->pevents & EV_POLLRDBAND) != 0) { + l_event->events |= LINUX_EPOLLRDBAND; + } + if ((kevent->pevents & EV_POLLWRBAND) != 0) { + l_event->events |= LINUX_EPOLLWRBAND; + } + + l_event->events = (l_event->events & kevent->pmask); } /* @@ -380,6 +413,8 @@ ciargs.changelist = kev; if (args->op != LINUX_EPOLL_CTL_DEL) { + /* For Linux, 'EPOLLERR' and 'EPOLLHUP' are always in mask. */ + le.events |= LINUX_EPOLLERR | LINUX_EPOLLHUP; error = epoll_to_kevent(td, args->fd, &le, kev, &nchanges); if (error != 0) goto leave0; Index: sys/kern/uipc_socket.c =================================================================== --- sys/kern/uipc_socket.c +++ sys/kern/uipc_socket.c @@ -3830,6 +3830,10 @@ kn->kn_data = sbavail(&so->so_rcv) - so->so_rcv.sb_ctl; if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { kn->kn_flags |= EV_EOF; + kn->kn_pevents |= EV_POLLIN | EV_POLLRDHUP | EV_POLLRDNORM; + if (so->so_snd.sb_state & SBS_CANTSENDMORE) { + kn->kn_pevents |= EV_POLLHUP; + } kn->kn_fflags = so->so_error; return (1); } else if (so->so_error) /* temporary udp error */ @@ -3875,6 +3879,10 @@ if (so->so_snd.sb_state & SBS_CANTSENDMORE) { kn->kn_flags |= EV_EOF; + if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { + kn->kn_pevents |= EV_POLLHUP + | EV_POLLIN | EV_POLLRDHUP | EV_POLLRDNORM; + } kn->kn_fflags = so->so_error; return (1); } else if (so->so_error) /* temporary udp error */ Index: sys/sys/event.h =================================================================== --- sys/sys/event.h +++ sys/sys/event.h @@ -33,6 +33,7 @@ #include #include +#include #define EVFILT_READ (-1) #define EVFILT_WRITE (-2) @@ -58,6 +59,8 @@ .fflags = (d), \ .data = (e), \ .udata = (f), \ + .pevents = 0, \ + .pmask = 0, \ .ext = {0}, \ }; \ } while(0) @@ -73,10 +76,11 @@ (kevp)->fflags = (d); \ (kevp)->data = (e); \ (kevp)->udata = (f); \ + (kevp)->pevents = 0; \ + (kevp)->pmask = 0; \ (kevp)->ext[0] = 0; \ (kevp)->ext[1] = 0; \ (kevp)->ext[2] = 0; \ - (kevp)->ext[3] = 0; \ } while(0) #endif @@ -87,7 +91,9 @@ unsigned int fflags; /* filter flag value */ __int64_t data; /* filter data value */ void *udata; /* opaque user data identifier */ - __uint64_t ext[4]; /* extensions */ + unsigned int pevents; /* poll events, used to Linux epoll */ + unsigned int pmask; /* poll mask, used to Linux epoll */ + __uint64_t ext[3]; /* extensions */ }; #if defined(_WANT_FREEBSD11_KEVENT) @@ -153,6 +159,19 @@ #define EV_EOF 0x8000 /* EOF detected */ #define EV_ERROR 0x4000 /* error, data contains errno */ +/* poll event */ +#define EV_POLLIN POLLIN +#define EV_POLLPRI POLLPRI +#define EV_POLLOUT POLLOUT +#define EV_POLLERR POLLERR +#define EV_POLLHUP POLLHUP +#define EV_POLLRDNORM POLLRDNORM +#define EV_POLLWRNORM POLLWRNORM +#define EV_POLLRDBAND POLLRDBAND +#define EV_POLLWRBAND POLLWRBAND +#define EV_POLLRDHUP 0x00002000 + + /* * data/hint flags/masks for EVFILT_USER, shared with userspace * @@ -311,6 +330,7 @@ #define kn_fflags kn_kevent.fflags #define kn_data kn_kevent.data #define kn_fp kn_ptr.p_fp +#define kn_pevents kn_kevent.pevents }; struct kevent_copyops { void *arg;