diff options
| author | Eli Zaretskii | 2014-09-14 18:18:39 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2014-09-14 18:18:39 +0300 |
| commit | 9ed670023f6d7534f0e812417fe13ab3cfadaa7a (patch) | |
| tree | 06b0c29a6085e82fdb3ddd02c15bd236c6d10006 /src | |
| parent | a6cc335aef90cb4a2dc3fde77cbea9886240301e (diff) | |
| download | emacs-9ed670023f6d7534f0e812417fe13ab3cfadaa7a.tar.gz emacs-9ed670023f6d7534f0e812417fe13ab3cfadaa7a.zip | |
Fix bug #18420 with deadlocks communicating with subprocess on MS-Windows.
src/w32.c (fcntl): Support O_NONBLOCK fcntl on the write side of
pipes.
(sys_write): When a write to a non-blocking pipe returns ENOSPC,
set errno to EAGAIN instead, to allow the caller to retry the
write after some waiting. Fixes deadlocks when Emacs exchanges a
lot of data through the pipe.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/w32.c | 54 |
2 files changed, 55 insertions, 8 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 4f851edb0fd..c32b4c44988 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2014-09-14 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * w32.c (fcntl): Support O_NONBLOCK fcntl on the write side of | ||
| 4 | pipes. | ||
| 5 | (sys_write): When a write to a non-blocking pipe returns ENOSPC, | ||
| 6 | set errno to EAGAIN instead, to allow the caller to retry the | ||
| 7 | write after some waiting. Fixes deadlocks when Emacs exchanges a | ||
| 8 | lot of data through the pipe. (Bug#18420) | ||
| 9 | |||
| 1 | 2014-09-13 Eli Zaretskii <eliz@gnu.org> | 10 | 2014-09-13 Eli Zaretskii <eliz@gnu.org> |
| 2 | 11 | ||
| 3 | * sound.c (Fplay_sound_internal): Encode the sound file name in | 12 | * sound.c (Fplay_sound_internal): Encode the sound file name in |
| @@ -7690,15 +7690,15 @@ fcntl (int s, int cmd, int options) | |||
| 7690 | if (cmd == F_DUPFD_CLOEXEC) | 7690 | if (cmd == F_DUPFD_CLOEXEC) |
| 7691 | return sys_dup (s); | 7691 | return sys_dup (s); |
| 7692 | 7692 | ||
| 7693 | if (winsock_lib == NULL) | ||
| 7694 | { | ||
| 7695 | errno = ENETDOWN; | ||
| 7696 | return -1; | ||
| 7697 | } | ||
| 7698 | |||
| 7699 | check_errno (); | 7693 | check_errno (); |
| 7700 | if (fd_info[s].flags & FILE_SOCKET) | 7694 | if (fd_info[s].flags & FILE_SOCKET) |
| 7701 | { | 7695 | { |
| 7696 | if (winsock_lib == NULL) | ||
| 7697 | { | ||
| 7698 | errno = ENETDOWN; | ||
| 7699 | return -1; | ||
| 7700 | } | ||
| 7701 | |||
| 7702 | if (cmd == F_SETFL && options == O_NONBLOCK) | 7702 | if (cmd == F_SETFL && options == O_NONBLOCK) |
| 7703 | { | 7703 | { |
| 7704 | unsigned long nblock = 1; | 7704 | unsigned long nblock = 1; |
| @@ -7715,13 +7715,36 @@ fcntl (int s, int cmd, int options) | |||
| 7715 | return SOCKET_ERROR; | 7715 | return SOCKET_ERROR; |
| 7716 | } | 7716 | } |
| 7717 | } | 7717 | } |
| 7718 | else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE)) | ||
| 7719 | == (FILE_PIPE | FILE_WRITE)) | ||
| 7720 | { | ||
| 7721 | /* Force our writes to pipes be non-blocking. */ | ||
| 7722 | if (cmd == F_SETFL && options == O_NONBLOCK) | ||
| 7723 | { | ||
| 7724 | HANDLE h = (HANDLE)_get_osfhandle (s); | ||
| 7725 | DWORD pipe_mode = PIPE_NOWAIT; | ||
| 7726 | |||
| 7727 | if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL)) | ||
| 7728 | { | ||
| 7729 | DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ())); | ||
| 7730 | return SOCKET_ERROR; | ||
| 7731 | } | ||
| 7732 | fd_info[s].flags |= FILE_NDELAY; | ||
| 7733 | return 0; | ||
| 7734 | } | ||
| 7735 | else | ||
| 7736 | { | ||
| 7737 | errno = EINVAL; | ||
| 7738 | return SOCKET_ERROR; | ||
| 7739 | } | ||
| 7740 | } | ||
| 7718 | errno = ENOTSOCK; | 7741 | errno = ENOTSOCK; |
| 7719 | return SOCKET_ERROR; | 7742 | return SOCKET_ERROR; |
| 7720 | } | 7743 | } |
| 7721 | 7744 | ||
| 7722 | 7745 | ||
| 7723 | /* Shadow main io functions: we need to handle pipes and sockets more | 7746 | /* Shadow main io functions: we need to handle pipes and sockets more |
| 7724 | intelligently, and implement non-blocking mode as well. */ | 7747 | intelligently. */ |
| 7725 | 7748 | ||
| 7726 | int | 7749 | int |
| 7727 | sys_close (int fd) | 7750 | sys_close (int fd) |
| @@ -8206,7 +8229,6 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 8206 | /* From w32xfns.c */ | 8229 | /* From w32xfns.c */ |
| 8207 | extern HANDLE interrupt_handle; | 8230 | extern HANDLE interrupt_handle; |
| 8208 | 8231 | ||
| 8209 | /* For now, don't bother with a non-blocking mode */ | ||
| 8210 | int | 8232 | int |
| 8211 | sys_write (int fd, const void * buffer, unsigned int count) | 8233 | sys_write (int fd, const void * buffer, unsigned int count) |
| 8212 | { | 8234 | { |
| @@ -8341,6 +8363,22 @@ sys_write (int fd, const void * buffer, unsigned int count) | |||
| 8341 | nchars += n; | 8363 | nchars += n; |
| 8342 | if (n < 0) | 8364 | if (n < 0) |
| 8343 | { | 8365 | { |
| 8366 | /* When there's no buffer space in a pipe that is in the | ||
| 8367 | non-blocking mode, _write returns ENOSPC. We return | ||
| 8368 | EAGAIN instead, which should trigger the logic in | ||
| 8369 | send_process that enters waiting loop and calls | ||
| 8370 | wait_reading_process_output to allow process input to | ||
| 8371 | be accepted during the wait. Those calls to | ||
| 8372 | wait_reading_process_output allow sys_select to | ||
| 8373 | notice when process input becomes available, thus | ||
| 8374 | avoiding deadlock whereby each side of the pipe is | ||
| 8375 | blocked on write, waiting for the other party to read | ||
| 8376 | its end of the pipe. */ | ||
| 8377 | if (errno == ENOSPC | ||
| 8378 | && fd < MAXDESC | ||
| 8379 | && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY)) | ||
| 8380 | == (FILE_PIPE | FILE_NDELAY))) | ||
| 8381 | errno = EAGAIN; | ||
| 8344 | nchars = n; | 8382 | nchars = n; |
| 8345 | break; | 8383 | break; |
| 8346 | } | 8384 | } |