# HG changeset patch # User Ilia Gromov # Date 1487527170 -10800 # Sun Feb 19 20:59:30 2017 +0300 # Branch release82 # Node ID 6ab106cff4111eafc10cd5e1e8174205bd58acfe # Parent 2bee8476b3f6908ff5bf7092c28295cd12b55f4d Fixing #267531 - Large pastes can lock up Term/AllOfNetBeans Getting rid of deadlock. Introduce buffer for a delayed write to master_fd. Reordered read/write master_fd blocks. diff --git a/dlight.nativeexecution/tools/pty/src/loop.c b/dlight.nativeexecution/tools/pty/src/loop.c --- a/dlight.nativeexecution/tools/pty/src/loop.c +++ b/dlight.nativeexecution/tools/pty/src/loop.c @@ -46,6 +46,7 @@ #include #include #include +#include "stdio.h" #ifndef INFTIM #define INFTIM -1 @@ -69,7 +70,7 @@ if (select_result == -1 && errno == EINTR) { continue; } - + if (select_result == -1) { err_sys("poll failed\n"); } @@ -109,10 +110,16 @@ #else +#define FRAGSIZ 1000 + int loop(int master_fd) { ssize_t n; - char buf[BUFSIZ]; + char buf[FRAGSIZ]; struct pollfd fds[2]; + + struct buffer to_master; + to_master.offset = 0; + to_master.length = 0; fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN; @@ -135,29 +142,8 @@ err_sys("poll() failed in main_loop"); } - if (fds[0].revents & POLLIN) { - if ((n = read(STDIN_FILENO, buf, BUFSIZ)) == -1) { - err_sys("read from stdin failed"); - } - - if (n == 0) { -#ifdef __CYGWIN__ - // On Windows when calling process is killed, - // POLLIN flag is set, not POLLHUP. - // So behave as if we have received POLLHUP in this case... - close(master_fd); - return 1; -#endif - break; - } - - if (writen(master_fd, buf, n) == -1) { - err_sys("write to master failed\n"); - } - } - if (fds[1].revents & POLLIN) { - if ((n = read(master_fd, buf, BUFSIZ)) == -1) { + if ((n = read(master_fd, buf, FRAGSIZ)) == -1) { #ifdef __CYGWIN__ // On Windows master_fd is invalid here // (bug #252202) @@ -177,6 +163,36 @@ } } + if (to_master.offset != to_master.length) { + int nwritten = writen_no_block(master_fd, &to_master); + if (nwritten == -1) { + err_sys("write to master failed\n"); + } + } else if (fds[0].revents & POLLIN) { + if ((n = read(STDIN_FILENO, to_master.buf, FRAGSIZ)) == -1) { + err_sys("read from stdin failed"); + } + + if (n == 0) { +#ifdef __CYGWIN__ + // On Windows when calling process is killed, + // POLLIN flag is set, not POLLHUP. + // So behave as if we have received POLLHUP in this case... + close(master_fd); + return 1; +#endif + break; + } + + to_master.offset = 0; + to_master.length = n; + + int nwritten = writen_no_block(master_fd, &to_master); + if (nwritten == -1) { + err_sys("write to master failed\n"); + } + } + if (fds[1].revents & POLLHUP) { break; } diff --git a/dlight.nativeexecution/tools/pty/src/util.c b/dlight.nativeexecution/tools/pty/src/util.c --- a/dlight.nativeexecution/tools/pty/src/util.c +++ b/dlight.nativeexecution/tools/pty/src/util.c @@ -39,6 +39,7 @@ */ #include "util.h" +#include "poll.h" ssize_t writen(int fd, const void *ptr, size_t n) { const char *pos = ptr; @@ -59,3 +60,33 @@ } return (n - nleft); /* return >= 0 */ } + +ssize_t writen_no_block(int fd, struct buffer *ptr) { + size_t n = ptr->length - ptr->offset; + size_t nleft = n; + ssize_t nwritten; + + int poll_block; + struct pollfd block[1]; + block[0].fd = fd; + block[0].events = POLLOUT; + block[0].revents = 0; + + while (nleft > 0) { + poll_block = poll((struct pollfd*) & block, 1, 1); + if (!(block[0].revents & POLLOUT)) { + break; + } + if ((nwritten = write(fd, ptr->buf + ptr->offset, nleft)) < 0) { + if (nleft == n) + return (-1); /* error, return -1 */ + else + break; /* error, return amount written so far */ + } else if (nwritten == 0) { + break; + } + nleft -= nwritten; + ptr->offset += nwritten; + } + return (n - nleft); /* return >= 0 */ +} diff --git a/dlight.nativeexecution/tools/pty/src/util.h b/dlight.nativeexecution/tools/pty/src/util.h --- a/dlight.nativeexecution/tools/pty/src/util.h +++ b/dlight.nativeexecution/tools/pty/src/util.h @@ -55,7 +55,14 @@ extern "C" { #endif + struct buffer{ + char buf[BUFSIZ]; + int offset; + int length; + }; + ssize_t writen(int fd, const void *ptr, size_t n); + ssize_t writen_no_block(int fd, struct buffer *ptr); #if defined (__CYGWIN__) || defined (WINDOWS) extern char *strsignal(int);