How to Get Errno When Epoll_Wait Returns Epollerr

How to get errno when epoll_wait returns EPOLLERR?

Use getsockopt and SO_ERROR to get the pending error on the socket

int       error = 0;
socklen_t errlen = sizeof(error);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == 0)
{
printf("error = %s\n", strerror(error));
}

meaning of EPOLLERR from epoll_wait with a pipe

Other than the other end being closed, there aren't any errors on a write end of a pipe which could be detected by epoll. The few errors that are possible on an actual call to write() could not be known in advance (e.g., if you pass an invalid buffer pointer), so epoll cannot detect them. Therefore, if epoll tells you there's an error, it is EPIPE.

(OK, there is actually another possible error condition, but it can be triggered only by a programming error: if you close the file descriptor and then use epoll_wait while it is on the list - I don't know how epoll will react to that).

c++ socket accept() get Resource deadlock avoided errno with epoll

Error code 11 is EAGAIN, which is a very common error code to encounter when dealing with non-blocking socket I/O. It means the requested operation has nothing to do, try it again later.

In the case of accept(), it means:

EAGAIN or EWOULDBLOCK

The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 and POSIX.1-2008 allow either error to be returned for this case, and do not require these constants to have the same value, so a portable application should check for both possibilities.

This means you are calling accept() at the wrong time, when the listening socket does not have any clients to accept. Double check your epoll() usage, it likely has a logic bug in it that is causing you to call accept() prematurely.

For instance, after accept() has successfully accepted a client, you are assigning the listening socket instead of the client socket to event.data.fd when calling epoll_ctl(EPOLL_CTL_ADD):

struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = serverFd; // <-- HERE, SHOULD BE acceptFd INSTEAD!
int ctlClientResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, acceptFd, &event);

As such, when the client has data waiting to be read, your loop will end up calling accept() on the listening socket instead of calling recv() on the client socket.

Also, you are not checking the reported event.events field for socket errors. If an error occurs on a client socket, the reported events may include the EPOLLERR and/or EPOLLHUP flags. You should check for those flags and if present then close the client socket, before checking for the EPOLLIN flag to call recv().

Also, note that in your example, it is not necessary to call epoll_ctl(EPOLL_CTL_DEL) before calling close() on a socket. Closing a socket file descriptor will automatically remove it from the epoll instance that is monitoring it.

epoll_wait fails due to EINTR, how to remedy this?

Certain signal handler will interrupt epoll_wait(), select() and similar system calls on any Unix or Linux. This is by design so you can interrupt these system calls.

You cannot directly remedy it. The typical solution is to explicitly check the errno for EINTR and to execute epoll_wait() again:

int nr;
do {
nr = epoll_wait(epfd, events, maxevents, timeout);
} while (nr < 0 && errno == EINTR);

Also see: gdb error: Unable to execute epoll_wait: (4) Interrupted system call

EBADF while recv after epoll_wait

When the remote host closes the socket, epoll() reports both a HUP and an EPOLLIN for the file descriptor.

You check for EPOLLRDHUP first, and close the socket; then you check for EPOLLIN, find that too, and try to call recv(). Since the socket has been closed, the file descriptor is no longer valid, and you get EBADF (the closed socket is removed from the epoll set, so subsequent epoll_wait() calls won't return it; but for the epoll_wait() that has already returned it's too late - the EPOLLIN is already waiting in your events[i].

You need to stop checking for events after you call disconnectDriver() (if it closed the file descriptor):

        if (events[i].events & EPOLLRDHUP) {
std::cout << "EPOLLRDHUP on " << events[i].data.fd << std::endl;
listener->disconnectDriver(events[i].data.fd);
continue;
}


Related Topics



Leave a reply



Submit