darwin: allocate enough space for select() hack
`fd_set`s are way too small for `select()` hack when stream's fd is bigger than 1023. Make `fd_set`s a part of `uv__stream_select_t` structure. fix #1461 Conflicts: src/unix/stream.c
This commit is contained in:
parent
71b7128987
commit
c60d6af011
@ -85,6 +85,7 @@ ifeq (__clang__,$(shell sh -c "$(CC) -dM -E - </dev/null | grep -ow __clang__"))
|
|||||||
CFLAGS += -Wno-dollar-in-identifier-extension
|
CFLAGS += -Wno-dollar-in-identifier-extension
|
||||||
endif
|
endif
|
||||||
CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
|
CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
|
||||||
|
CPPFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
|
||||||
LDFLAGS += -framework Foundation \
|
LDFLAGS += -framework Foundation \
|
||||||
-framework CoreServices \
|
-framework CoreServices \
|
||||||
-framework ApplicationServices
|
-framework ApplicationServices
|
||||||
|
|||||||
@ -53,6 +53,10 @@ struct uv__stream_select_s {
|
|||||||
int fake_fd;
|
int fake_fd;
|
||||||
int int_fd;
|
int int_fd;
|
||||||
int fd;
|
int fd;
|
||||||
|
fd_set* sread;
|
||||||
|
size_t sread_sz;
|
||||||
|
fd_set* swrite;
|
||||||
|
size_t swrite_sz;
|
||||||
};
|
};
|
||||||
#endif /* defined(__APPLE__) */
|
#endif /* defined(__APPLE__) */
|
||||||
|
|
||||||
@ -131,8 +135,6 @@ static void uv__stream_osx_select(void* arg) {
|
|||||||
uv_stream_t* stream;
|
uv_stream_t* stream;
|
||||||
uv__stream_select_t* s;
|
uv__stream_select_t* s;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
fd_set sread;
|
|
||||||
fd_set swrite;
|
|
||||||
int events;
|
int events;
|
||||||
int fd;
|
int fd;
|
||||||
int r;
|
int r;
|
||||||
@ -153,17 +155,17 @@ static void uv__stream_osx_select(void* arg) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Watch fd using select(2) */
|
/* Watch fd using select(2) */
|
||||||
FD_ZERO(&sread);
|
memset(s->sread, 0, s->sread_sz);
|
||||||
FD_ZERO(&swrite);
|
memset(s->swrite, 0, s->swrite_sz);
|
||||||
|
|
||||||
if (uv_is_readable(stream))
|
if (uv_is_readable(stream))
|
||||||
FD_SET(fd, &sread);
|
FD_SET(fd, s->sread);
|
||||||
if (uv_is_writable(stream))
|
if (uv_is_writable(stream))
|
||||||
FD_SET(fd, &swrite);
|
FD_SET(fd, s->swrite);
|
||||||
FD_SET(s->int_fd, &sread);
|
FD_SET(s->int_fd, s->sread);
|
||||||
|
|
||||||
/* Wait indefinitely for fd events */
|
/* Wait indefinitely for fd events */
|
||||||
r = select(max_fd + 1, &sread, &swrite, NULL, NULL);
|
r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
@ -177,7 +179,7 @@ static void uv__stream_osx_select(void* arg) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Empty socketpair's buffer in case of interruption */
|
/* Empty socketpair's buffer in case of interruption */
|
||||||
if (FD_ISSET(s->int_fd, &sread))
|
if (FD_ISSET(s->int_fd, s->sread))
|
||||||
while (1) {
|
while (1) {
|
||||||
r = read(s->int_fd, buf, sizeof(buf));
|
r = read(s->int_fd, buf, sizeof(buf));
|
||||||
|
|
||||||
@ -198,12 +200,12 @@ static void uv__stream_osx_select(void* arg) {
|
|||||||
|
|
||||||
/* Handle events */
|
/* Handle events */
|
||||||
events = 0;
|
events = 0;
|
||||||
if (FD_ISSET(fd, &sread))
|
if (FD_ISSET(fd, s->sread))
|
||||||
events |= UV__POLLIN;
|
events |= UV__POLLIN;
|
||||||
if (FD_ISSET(fd, &swrite))
|
if (FD_ISSET(fd, s->swrite))
|
||||||
events |= UV__POLLOUT;
|
events |= UV__POLLOUT;
|
||||||
|
|
||||||
assert(events != 0 || FD_ISSET(s->int_fd, &sread));
|
assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
|
||||||
if (events != 0) {
|
if (events != 0) {
|
||||||
ACCESS_ONCE(int, s->events) = events;
|
ACCESS_ONCE(int, s->events) = events;
|
||||||
|
|
||||||
@ -283,6 +285,10 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
|
|||||||
int ret;
|
int ret;
|
||||||
int kq;
|
int kq;
|
||||||
int old_fd;
|
int old_fd;
|
||||||
|
int max_fd;
|
||||||
|
size_t sread_sz;
|
||||||
|
size_t swrite_sz;
|
||||||
|
int err;
|
||||||
|
|
||||||
kq = kqueue();
|
kq = kqueue();
|
||||||
if (kq == -1) {
|
if (kq == -1) {
|
||||||
@ -306,30 +312,52 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* At this point we definitely know that this fd won't work with kqueue */
|
/* At this point we definitely know that this fd won't work with kqueue */
|
||||||
s = malloc(sizeof(*s));
|
|
||||||
if (s == NULL)
|
/*
|
||||||
return uv__set_artificial_error(stream->loop, UV_ENOMEM);
|
* Create fds for io watcher and to interrupt the select() loop.
|
||||||
|
* NOTE: do it ahead of malloc below to allocate enough space for fd_sets
|
||||||
|
*/
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
|
||||||
|
return uv__set_sys_error(stream->loop, errno);
|
||||||
|
|
||||||
|
max_fd = *fd;
|
||||||
|
if (fds[1] > max_fd)
|
||||||
|
max_fd = fds[1];
|
||||||
|
|
||||||
|
sread_sz = (max_fd + NBBY) / NBBY;
|
||||||
|
swrite_sz = sread_sz;
|
||||||
|
|
||||||
|
s = malloc(sizeof(*s) + sread_sz + swrite_sz);
|
||||||
|
if (s == NULL) {
|
||||||
|
err = uv__set_artificial_error(stream->loop, UV_ENOMEM);
|
||||||
|
goto failed_malloc;
|
||||||
|
}
|
||||||
|
|
||||||
s->events = 0;
|
s->events = 0;
|
||||||
s->fd = *fd;
|
s->fd = *fd;
|
||||||
|
s->sread = (fd_set*) ((char*) s + sizeof(*s));
|
||||||
|
s->sread_sz = sread_sz;
|
||||||
|
s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
|
||||||
|
s->swrite_sz = swrite_sz;
|
||||||
|
|
||||||
if (uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb)) {
|
err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
|
||||||
SAVE_ERRNO(free(s));
|
if (err)
|
||||||
return uv__set_sys_error(stream->loop, errno);
|
goto failed_async_init;
|
||||||
}
|
|
||||||
|
|
||||||
s->async.flags |= UV__HANDLE_INTERNAL;
|
s->async.flags |= UV__HANDLE_INTERNAL;
|
||||||
uv__handle_unref(&s->async);
|
uv__handle_unref(&s->async);
|
||||||
|
|
||||||
if (uv_sem_init(&s->close_sem, 0))
|
err = uv_sem_init(&s->close_sem, 0);
|
||||||
goto fatal1;
|
if (err != 0) {
|
||||||
|
err = uv__set_sys_error(stream->loop, UV_UNKNOWN);
|
||||||
|
goto failed_close_sem_init;
|
||||||
|
}
|
||||||
|
|
||||||
if (uv_sem_init(&s->async_sem, 0))
|
err = uv_sem_init(&s->async_sem, 0);
|
||||||
goto fatal2;
|
if (err != 0) {
|
||||||
|
err = uv__set_sys_error(stream->loop, UV_UNKNOWN);
|
||||||
/* Create fds for io watcher and to interrupt the select() loop. */
|
goto failed_async_sem_init;
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
|
}
|
||||||
goto fatal3;
|
|
||||||
|
|
||||||
s->fake_fd = fds[0];
|
s->fake_fd = fds[0];
|
||||||
s->int_fd = fds[1];
|
s->int_fd = fds[1];
|
||||||
@ -339,26 +367,37 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
|
|||||||
stream->select = s;
|
stream->select = s;
|
||||||
*fd = s->fake_fd;
|
*fd = s->fake_fd;
|
||||||
|
|
||||||
if (uv_thread_create(&s->thread, uv__stream_osx_select, stream))
|
err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
|
||||||
goto fatal4;
|
if (err != 0) {
|
||||||
|
err = uv__set_sys_error(stream->loop, UV_UNKNOWN);
|
||||||
|
goto failed_thread_create;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fatal4:
|
failed_thread_create:
|
||||||
s->stream = NULL;
|
s->stream = NULL;
|
||||||
stream->select = NULL;
|
stream->select = NULL;
|
||||||
*fd = old_fd;
|
*fd = old_fd;
|
||||||
close(s->fake_fd);
|
|
||||||
close(s->int_fd);
|
|
||||||
s->fake_fd = -1;
|
|
||||||
s->int_fd = -1;
|
|
||||||
fatal3:
|
|
||||||
uv_sem_destroy(&s->async_sem);
|
uv_sem_destroy(&s->async_sem);
|
||||||
fatal2:
|
|
||||||
|
failed_async_sem_init:
|
||||||
uv_sem_destroy(&s->close_sem);
|
uv_sem_destroy(&s->close_sem);
|
||||||
fatal1:
|
|
||||||
|
failed_close_sem_init:
|
||||||
|
close(fds[0]);
|
||||||
|
close(fds[1]);
|
||||||
uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
|
uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
|
||||||
return uv__set_sys_error(stream->loop, errno);
|
return err;
|
||||||
|
|
||||||
|
failed_async_init:
|
||||||
|
free(s);
|
||||||
|
|
||||||
|
failed_malloc:
|
||||||
|
close(fds[0]);
|
||||||
|
close(fds[1]);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
#endif /* defined(__APPLE__) */
|
#endif /* defined(__APPLE__) */
|
||||||
|
|
||||||
|
|||||||
@ -232,6 +232,7 @@ TEST_DECLARE (closed_fd_events)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
TEST_DECLARE (osx_select)
|
TEST_DECLARE (osx_select)
|
||||||
|
TEST_DECLARE (osx_select_many_fds)
|
||||||
#endif
|
#endif
|
||||||
HELPER_DECLARE (tcp4_echo_server)
|
HELPER_DECLARE (tcp4_echo_server)
|
||||||
HELPER_DECLARE (tcp6_echo_server)
|
HELPER_DECLARE (tcp6_echo_server)
|
||||||
@ -468,6 +469,7 @@ TASK_LIST_START
|
|||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
TEST_ENTRY (osx_select)
|
TEST_ENTRY (osx_select)
|
||||||
|
TEST_ENTRY (osx_select_many_fds)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_ENTRY (fs_file_noent)
|
TEST_ENTRY (fs_file_noent)
|
||||||
|
|||||||
@ -79,4 +79,51 @@ TEST_IMPL(osx_select) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_IMPL(osx_select_many_fds) {
|
||||||
|
int r;
|
||||||
|
int fd;
|
||||||
|
size_t i;
|
||||||
|
size_t len;
|
||||||
|
const char* str;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
uv_tty_t tty;
|
||||||
|
uv_tcp_t tcps[1500];
|
||||||
|
|
||||||
|
addr = uv_ip4_addr("127.0.0.1", 0);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tcps); i++) {
|
||||||
|
r = uv_tcp_init(uv_default_loop(), &tcps[i]);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
r = uv_tcp_bind(&tcps[i], addr);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
uv_unref((uv_handle_t*) &tcps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open("/dev/tty", O_RDONLY);
|
||||||
|
ASSERT(fd >= 0);
|
||||||
|
|
||||||
|
r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
/* Emulate user-input */
|
||||||
|
str = "got some input\n"
|
||||||
|
"with a couple of lines\n"
|
||||||
|
"feel pretty happy\n";
|
||||||
|
for (i = 0, len = strlen(str); i < len; i++) {
|
||||||
|
r = ioctl(fd, TIOCSTI, str + i);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
ASSERT(read_count == 3);
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __APPLE__ */
|
#endif /* __APPLE__ */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user