Skip to content

Commit 011ea03

Browse files
committed
fix #105 EINTR handled too defensively when polling
1 parent 695c7a3 commit 011ea03

File tree

9 files changed

+189
-212
lines changed

9 files changed

+189
-212
lines changed

CMake/_Include.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,11 @@ check_type(in_port_t netinet/in.h)
134134
check_type(pid_t sys/types.h)
135135
check_type(ssize_t sys/types.h)
136136
check_type("struct msghdr" sys/socket.h)
137+
check_type("struct timespec" time.h)
137138

138139
check_cxx_symbol(abi::__cxa_demangle cxxabi.h)
140+
check_symbol(CLOCK_MONOTONIC time.h)
141+
check_symbol(clock_gettime time.h)
139142
check_symbol(ERESTART errno.h)
140143
check_symbol(fcntl fcntl.h)
141144
check_symbol(gettimeofday sys/time.h)

ChangeLog-1.1.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# ChangeLog v1.1
22

3+
## v 1.1.0-beta3
4+
5+
> TBR
6+
7+
**Changes from beta2:**
8+
9+
* Fix [gh #105](https://github.com/m6w6/libmemcached/issues/105):
10+
EINTR handled too defensively when polling.
11+
312
## v 1.1.0-beta2
413

514
> released 2020-12-28

docs/source/ChangeLog-1.1.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@
55
ChangeLog v1.1
66
==============
77

8+
v 1.1.0-beta3
9+
-------------
10+
11+
..
12+
13+
TBR
14+
15+
16+
**Changes from beta2:**
17+
18+
19+
* Fix `gh #105 <https://github.com/m6w6/libmemcached/issues/105>`_\ :
20+
EINTR handled too defensively when polling.
21+
822
v 1.1.0-beta2
923
-------------
1024

src/libmemcached/connect.cc

Lines changed: 1 addition & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -19,128 +19,6 @@
1919
#include <cassert>
2020

2121

22-
static memcached_return_t connect_poll(memcached_instance_st *server, const int connection_error) {
23-
struct pollfd fds[1];
24-
fds[0].fd = server->fd;
25-
fds[0].events = server->events();
26-
fds[0].revents = 0;
27-
28-
size_t loop_max = 5;
29-
30-
if (server->root->connect_timeout == 0) {
31-
return memcached_set_error(
32-
*server, MEMCACHED_TIMEOUT, MEMCACHED_AT,
33-
memcached_literal_param("The time to wait for a connection to be established was set to "
34-
"zero which produces a timeout to every call to poll()."));
35-
}
36-
37-
while (--loop_max) // Should only loop on cases of ERESTART or EINTR
38-
{
39-
int number_of;
40-
if ((number_of = poll(fds, 1, server->root->connect_timeout)) == SOCKET_ERROR) {
41-
int local_errno = get_socket_errno(); // We cache in case closesocket() modifies errno
42-
switch (local_errno) {
43-
#ifdef HAVE_ERESTART
44-
case ERESTART:
45-
#endif
46-
case EINTR:
47-
continue;
48-
49-
case EFAULT:
50-
case ENOMEM:
51-
return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
52-
53-
case EINVAL:
54-
return memcached_set_error(
55-
*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
56-
memcached_literal_param(
57-
"RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid"));
58-
59-
default: // This should not happen
60-
break;
61-
}
62-
63-
assert_msg(server->fd != INVALID_SOCKET, "poll() was passed an invalid file descriptor");
64-
server->reset_socket();
65-
server->state = MEMCACHED_SERVER_STATE_NEW;
66-
67-
return memcached_set_errno(*server, local_errno, MEMCACHED_AT);
68-
}
69-
70-
if (number_of == 0) {
71-
if (connection_error != EALREADY) {
72-
int err;
73-
socklen_t len = sizeof(err);
74-
if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) {
75-
return memcached_set_errno(
76-
*server, errno, MEMCACHED_AT,
77-
memcached_literal_param(
78-
"getsockopt() error'ed while looking for error connect_poll(EINPROGRESS)"));
79-
}
80-
81-
// If Zero, my hero, we just fail to a generic MEMCACHED_TIMEOUT error
82-
if (err) {
83-
return memcached_set_errno(
84-
*server, err, MEMCACHED_AT,
85-
memcached_literal_param("getsockopt() found the error from poll() after connect() "
86-
"returned EINPROGRESS."));
87-
}
88-
}
89-
90-
return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT,
91-
memcached_literal_param("(number_of == 0)"));
92-
}
93-
94-
assert(number_of == 1);
95-
96-
if (fds[0].revents & POLLERR or fds[0].revents & POLLHUP or fds[0].revents & POLLNVAL) {
97-
int err;
98-
socklen_t len = sizeof(err);
99-
if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) {
100-
return memcached_set_errno(
101-
*server, errno, MEMCACHED_AT,
102-
memcached_literal_param(
103-
"getsockopt() errored while looking up error state from poll()"));
104-
}
105-
106-
// We check the value to see what happened with the socket.
107-
if (err == 0) // Should not happen
108-
{
109-
return MEMCACHED_SUCCESS;
110-
}
111-
errno = err;
112-
113-
return memcached_set_errno(
114-
*server, err, MEMCACHED_AT,
115-
memcached_literal_param("getsockopt() found the error from poll() during connect."));
116-
}
117-
assert(fds[0].revents & POLLOUT);
118-
119-
if (fds[0].revents & POLLOUT and connection_error != EALREADY) {
120-
int err;
121-
socklen_t len = sizeof(err);
122-
if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) {
123-
return memcached_set_errno(*server, errno, MEMCACHED_AT);
124-
}
125-
126-
if (err == 0) {
127-
return MEMCACHED_SUCCESS;
128-
}
129-
130-
return memcached_set_errno(
131-
*server, err, MEMCACHED_AT,
132-
memcached_literal_param(
133-
"getsockopt() found the error from poll() after connect() returned EINPROGRESS."));
134-
}
135-
136-
break; // We only have the loop setup for errno types that require restart
137-
}
138-
139-
// This should only be possible from ERESTART or EINTR;
140-
return memcached_set_errno(*server, connection_error, MEMCACHED_AT,
141-
memcached_literal_param("connect_poll() was exhausted"));
142-
}
143-
14422
static memcached_return_t set_hostinfo(memcached_instance_st *server) {
14523
assert(server->type != MEMCACHED_CONNECTION_UNIX_SOCKET);
14624
server->clear_addrinfo();
@@ -505,7 +383,7 @@ static memcached_return_t network_connect(memcached_instance_st *server) {
505383
{
506384
server->events(POLLOUT);
507385
server->state = MEMCACHED_SERVER_STATE_IN_PROGRESS;
508-
memcached_return_t rc = connect_poll(server, local_error);
386+
memcached_return_t rc = memcached_io_poll(server, IO_POLL_CONNECT, local_error);
509387

510388
if (memcached_success(rc)) {
511389
server->state = MEMCACHED_SERVER_STATE_CONNECTED;

0 commit comments

Comments
 (0)