diff --git a/Makefile.am b/Makefile.am index 0ef781ff198..1fd09a5e26e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -151,6 +151,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ + test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ test/test-error.c \ diff --git a/src/unix/fs.c b/src/unix/fs.c index 57b65be25a8..b090d063cf0 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -826,7 +826,8 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); -static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { +static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process, + int retry_on_eintr) { unsigned int iovmax; unsigned int nbufs; uv_buf_t* bufs; @@ -858,9 +859,14 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) total += result; } + if (errno == EINTR && total == -1 && retry_on_eintr) + return total; + if (bufs != req->bufsml) uv__free(bufs); + req->bufs = NULL; + req->nbufs = 0; return total; } @@ -899,7 +905,7 @@ static void uv__fs_work(struct uv__work* w) { X(MKDIR, mkdir(req->path, req->mode)); X(MKDTEMP, uv__fs_mkdtemp(req)); X(OPEN, uv__fs_open(req)); - X(READ, uv__fs_buf_iter(req, uv__fs_read)); + X(READ, uv__fs_buf_iter(req, uv__fs_read, retry_on_eintr)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); X(REALPATH, uv__fs_realpath(req)); @@ -910,7 +916,7 @@ static void uv__fs_work(struct uv__work* w) { X(SYMLINK, symlink(req->path, req->new_path)); X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); - X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); + X(WRITE, uv__fs_buf_iter(req, uv__fs_write, retry_on_eintr)); default: abort(); } #undef X diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c new file mode 100644 index 00000000000..a2849b82199 --- /dev/null +++ b/test/test-eintr-handling.c @@ -0,0 +1,72 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; + +static char buf[32]; +static uv_buf_t iov; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + kill(getpid(), SIGUSR1); + write(pipe_fds[1], test_buf, sizeof(test_buf)); +} + +void sig_func(int sig) { + printf("Caught signal: %d\n",sig); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + int nread; + + struct sigaction sig_handler = {.sa_handler=sig_func}; + sigaction(SIGUSR1,&sig_handler, 0); + + iov = uv_buf_init(buf, sizeof(buf)); + loop = uv_default_loop(); + + ASSERT(0 == pipe(pipe_fds)); + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); + + ASSERT(nread == sizeof(test_buf)); + ASSERT(0 == strcmp(buf, test_buf)); + + close(pipe_fds[0]); + close(pipe_fds[1]); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index d1eaf2ac920..42315b35da7 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -192,6 +192,7 @@ TEST_DECLARE (active) TEST_DECLARE (embed) TEST_DECLARE (async) TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) @@ -568,6 +569,7 @@ TASK_LIST_START TEST_ENTRY (async) TEST_ENTRY (async_null_cb) + TEST_ENTRY (eintr_handling) TEST_ENTRY (get_currentexe) diff --git a/uv.gyp b/uv.gyp index 635a234ea6e..c3734ba3f69 100644 --- a/uv.gyp +++ b/uv.gyp @@ -300,6 +300,7 @@ 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', + 'test/test-eintr-handling.c', 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c',