diff options
Diffstat (limited to 'lib/isc/unix/socket.c')
-rw-r--r-- | lib/isc/unix/socket.c | 94 |
1 files changed, 79 insertions, 15 deletions
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 5e6320d821c6a..42fc47f6deaaa 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -394,6 +394,9 @@ struct isc__socketmgr { /* Locked by fdlock. */ isc__socket_t **fds; int *fdstate; +#if defined(USE_EPOLL) + uint32_t *epoll_events; +#endif #ifdef USE_DEVPOLL pollinfo_t *fdpollinfo; #endif @@ -835,15 +838,27 @@ watch_fd(isc__socketmgr_t *manager, int fd, int msg) { return (result); #elif defined(USE_EPOLL) struct epoll_event event; + uint32_t oldevents; + int ret; + int op; + oldevents = manager->epoll_events[fd]; if (msg == SELECT_POKE_READ) - event.events = EPOLLIN; + manager->epoll_events[fd] |= EPOLLIN; else - event.events = EPOLLOUT; + manager->epoll_events[fd] |= EPOLLOUT; + + event.events = manager->epoll_events[fd]; memset(&event.data, 0, sizeof(event.data)); event.data.fd = fd; - if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1 && - errno != EEXIST) { + + op = (oldevents == 0U) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; + ret = epoll_ctl(manager->epoll_fd, op, fd, &event); + if (ret == -1) { + if (errno == EEXIST) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "epoll_ctl(ADD/MOD) returned " + "EEXIST for fd %d", fd); result = isc__errno2result(errno); } @@ -903,15 +918,21 @@ unwatch_fd(isc__socketmgr_t *manager, int fd, int msg) { return (result); #elif defined(USE_EPOLL) struct epoll_event event; + int ret; + int op; if (msg == SELECT_POKE_READ) - event.events = EPOLLIN; + manager->epoll_events[fd] &= ~(EPOLLIN); else - event.events = EPOLLOUT; + manager->epoll_events[fd] &= ~(EPOLLOUT); + + event.events = manager->epoll_events[fd]; memset(&event.data, 0, sizeof(event.data)); event.data.fd = fd; - if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_DEL, fd, &event) == -1 && - errno != ENOENT) { + + op = (event.events == 0U) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; + ret = epoll_ctl(manager->epoll_fd, op, fd, &event); + if (ret == -1 && errno != ENOENT) { char strbuf[ISC_STRERRORSIZE]; isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, @@ -1553,15 +1574,19 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, msg->msg_iovlen = iovcount; #ifdef ISC_NET_BSD44MSGHDR - msg->msg_control = NULL; - msg->msg_controllen = 0; - msg->msg_flags = 0; #if defined(USE_CMSG) if (sock->type == isc_sockettype_udp) { msg->msg_control = sock->recvcmsgbuf; msg->msg_controllen = sock->recvcmsgbuflen; + } else { + msg->msg_control = NULL; + msg->msg_controllen = 0; } +#else + msg->msg_control = NULL; + msg->msg_controllen = 0; #endif /* USE_CMSG */ + msg->msg_flags = 0; #else /* ISC_NET_BSD44MSGHDR */ msg->msg_accrights = NULL; msg->msg_accrightslen = 0; @@ -1872,8 +1897,11 @@ doio_send(isc__socket_t *sock, isc_socketevent_t *dev) { if (send_errno == EINTR && ++attempts < NRETRIES) goto resend; - if (SOFT_ERROR(send_errno)) + if (SOFT_ERROR(send_errno)) { + if (errno == EWOULDBLOCK || errno == EAGAIN) + dev->result = ISC_R_WOULDBLOCK; return (DOIO_SOFT); + } #define SOFT_OR_HARD(_system, _isc) \ if (send_errno == _system) { \ @@ -2035,7 +2063,7 @@ destroy(isc__socket_t **sockp) { INSIST(ISC_LIST_EMPTY(sock->recv_list)); INSIST(ISC_LIST_EMPTY(sock->send_list)); INSIST(sock->connect_ev == NULL); - REQUIRE(sock->fd == -1 || sock->fd < (int)manager->maxsocks); + INSIST(sock->fd >= -1 && sock->fd < (int)manager->maxsocks); if (sock->fd >= 0) { fd = sock->fd; @@ -2192,8 +2220,8 @@ static void free_socket(isc__socket_t **socketp) { isc__socket_t *sock = *socketp; - INSIST(sock->references == 0); INSIST(VALID_SOCKET(sock)); + INSIST(sock->references == 0); INSIST(!sock->connecting); INSIST(!sock->pending_recv); INSIST(!sock->pending_send); @@ -2633,6 +2661,9 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, LOCK(&manager->fdlock[lockid]); manager->fds[sock->fd] = sock; manager->fdstate[sock->fd] = MANAGED; +#if defined(USE_EPOLL) + manager->epoll_events[sock->fd] = 0; +#endif #ifdef USE_DEVPOLL INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 && sock->manager->fdpollinfo[sock->fd].want_write == 0); @@ -2710,6 +2741,9 @@ isc__socket_open(isc_socket_t *sock0) { LOCK(&sock->manager->fdlock[lockid]); sock->manager->fds[sock->fd] = sock; sock->manager->fdstate[sock->fd] = MANAGED; +#if defined(USE_EPOLL) + sock->manager->epoll_events[sock->fd] = 0; +#endif #ifdef USE_DEVPOLL INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 && sock->manager->fdpollinfo[sock->fd].want_write == 0); @@ -2747,6 +2781,9 @@ isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags, REQUIRE(VALID_MANAGER(manager)); REQUIRE(socketp != NULL && *socketp == NULL); + if (fd < 0 || (unsigned int)fd >= manager->maxsocks) + return (ISC_R_RANGE); + result = allocate_socket(manager, isc_sockettype_fdwatch, &sock); if (result != ISC_R_SUCCESS) return (result); @@ -2771,6 +2808,9 @@ isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags, LOCK(&manager->fdlock[lockid]); manager->fds[sock->fd] = sock; manager->fdstate[sock->fd] = MANAGED; +#if defined(USE_EPOLL) + manager->epoll_events[sock->fd] = 0; +#endif UNLOCK(&manager->fdlock[lockid]); LOCK(&manager->lock); @@ -3310,6 +3350,9 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { LOCK(&manager->fdlock[lockid]); manager->fds[fd] = NEWCONNSOCK(dev); manager->fdstate[fd] = MANAGED; +#if defined(USE_EPOLL) + manager->epoll_events[fd] = 0; +#endif UNLOCK(&manager->fdlock[lockid]); LOCK(&manager->lock); @@ -4260,6 +4303,15 @@ isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, result = ISC_R_NOMEMORY; goto free_manager; } +#if defined(USE_EPOLL) + manager->epoll_events = isc_mem_get(mctx, (manager->maxsocks * + sizeof(uint32_t))); + if (manager->epoll_events == NULL) { + result = ISC_R_NOMEMORY; + goto free_manager; + } + memset(manager->epoll_events, 0, manager->maxsocks * sizeof(uint32_t)); +#endif manager->stats = NULL; manager->common.methods = &socketmgrmethods; @@ -4329,7 +4381,9 @@ isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, result = setup_watcher(mctx, manager); if (result != ISC_R_SUCCESS) goto cleanup; + memset(manager->fdstate, 0, manager->maxsocks * sizeof(int)); + #ifdef USE_WATCHER_THREAD /* * Start up the select/poll thread. @@ -4378,6 +4432,12 @@ free_manager: isc_mem_put(mctx, manager->fdlock, FDLOCK_COUNT * sizeof(isc_mutex_t)); } +#if defined(USE_EPOLL) + if (manager->epoll_events != NULL) { + isc_mem_put(mctx, manager->epoll_events, + manager->maxsocks * sizeof(uint32_t)); + } +#endif if (manager->fdstate != NULL) { isc_mem_put(mctx, manager->fdstate, manager->maxsocks * sizeof(int)); @@ -4493,6 +4553,10 @@ isc__socketmgr_destroy(isc_socketmgr_t **managerp) { if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */ (void)close(i); +#if defined(USE_EPOLL) + isc_mem_put(manager->mctx, manager->epoll_events, + manager->maxsocks * sizeof(uint32_t)); +#endif isc_mem_put(manager->mctx, manager->fds, manager->maxsocks * sizeof(isc__socket_t *)); isc_mem_put(manager->mctx, manager->fdstate, |