Skip to content

Commit 52ab68f

Browse files
stevenhbcui6611
authored andcommitted
MB-8102: Switched from using select(..) to poll(..) within mcs_io_read
This prevent segfaults when more than 1024 fd's are used. Change-Id: I5513af3fdeca6d807d14d5977e9ca2cb5b2c8719 Reviewed-on: http://review.couchbase.org/30345 Reviewed-by: Steve Yen <[email protected]> Tested-by: Bin Cui <[email protected]>
1 parent db427f1 commit 52ab68f

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

mcs.c

+79
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#include <unistd.h>
99
#include <fcntl.h>
1010
#include <assert.h>
11+
#ifndef WIN32
12+
#include <poll.h>
13+
#include <limits.h>
14+
#endif
1115
#include "memcached.h"
1216
#include "cproxy.h"
1317
#include "mcs.h"
@@ -16,6 +20,9 @@
1620
/* TODO: This timeout is inherited from zstored, but use it where? */
1721

1822
#define DOWNSTREAM_DEFAULT_LINGER 1000
23+
#ifndef INFTIM
24+
#define INFTIM -1
25+
#endif
1926

2027
/* The lvb stands for libvbucket. */
2128

@@ -584,6 +591,7 @@ ssize_t mcs_io_write(int fd, const void *buffer, size_t length) {
584591
return write(fd, buffer, length);
585592
}
586593

594+
#ifdef WIN32
587595
mcs_return mcs_io_read(int fd, void *dta, size_t size, struct timeval *timeout_in) {
588596
struct timeval my_timeout; /* Linux select() modifies its timeout param. */
589597
struct timeval *timeout = NULL;
@@ -626,6 +634,77 @@ mcs_return mcs_io_read(int fd, void *dta, size_t size, struct timeval *timeout_i
626634

627635
return MCS_SUCCESS;
628636
}
637+
#else
638+
639+
static unsigned long long __get_time_ms(const struct timeval *tv) {
640+
struct timeval now;
641+
642+
if (tv == NULL) {
643+
if (gettimeofday(&now, NULL) != 0) {
644+
return 0;
645+
}
646+
tv = &now;
647+
}
648+
return (unsigned long long)tv->tv_sec * 1000 + (unsigned long long)tv->tv_usec / 1000;
649+
}
650+
651+
mcs_return mcs_io_read(int fd, void *dta, size_t size, struct timeval *timeout_in) {
652+
unsigned long long start_ms = 0;
653+
unsigned long long timeout_ms = 0;
654+
unsigned long long now_ms = 0;
655+
656+
if (timeout_in != NULL) {
657+
start_ms = __get_time_ms(NULL);
658+
timeout_ms = __get_time_ms(timeout_in);
659+
now_ms = start_ms;
660+
}
661+
662+
char *data = dta;
663+
size_t done = 0;
664+
struct pollfd pfd[1];
665+
666+
while (done < size) {
667+
pfd[0].fd = fd;
668+
pfd[0].events = POLLIN;
669+
pfd[0].revents = 0;
670+
671+
int timeout = INFTIM;
672+
if (timeout_in != NULL) {
673+
if (timeout_ms == 0) {
674+
/* ensure we poll at least once */
675+
timeout = 0;
676+
} else {
677+
unsigned long long taken_ms = now_ms - start_ms;
678+
if (taken_ms >= timeout_ms) {
679+
/* just check (boundary case) */
680+
timeout = 0;
681+
} else {
682+
unsigned long long left_ms = timeout_ms - taken_ms;
683+
timeout = (left_ms > INT_MAX) ? INT_MAX : left_ms;
684+
}
685+
}
686+
}
687+
int s = poll(pfd, 1, timeout);
688+
if (s == 0) {
689+
return MCS_TIMEOUT;
690+
}
691+
692+
if (s != 1 || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)) || !(pfd[0].revents & POLLIN)) {
693+
return MCS_FAILURE;
694+
}
695+
696+
ssize_t n = read(fd, data + done, 1);
697+
if (n == -1 || n == 0) {
698+
return MCS_FAILURE;
699+
}
700+
701+
done += (size_t) n;
702+
now_ms = __get_time_ms(NULL);
703+
}
704+
705+
return MCS_SUCCESS;
706+
}
707+
#endif
629708

630709
void mcs_io_reset(int fd) {
631710
(void) fd;

0 commit comments

Comments
 (0)