aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2022-07-17 15:44:50 +0300
committerEli Zaretskii2022-07-17 15:44:50 +0300
commit637436970f34f860d50f73a514b3bafd0c5cace7 (patch)
treef9f1fba2434ad07a84eecade8f0306d2be4111e2 /src
parent202c12a24b89a3b8a923adba4d6bab0894b1a16e (diff)
downloademacs-637436970f34f860d50f73a514b3bafd0c5cace7.tar.gz
emacs-637436970f34f860d50f73a514b3bafd0c5cace7.zip
Fix leaking of file descriptors due to pipe processes on MS-Windows
* src/w32proc.c (reader_thread): Wait for 'sys_close' to finish processing the pipe read descriptor, before trying to close it. * src/w32.c (sys_close): Attempt to detect when the reader thread already exited, so that it would be possible to close descriptors open by pipe processes for reading from the pipe. (Bug#56606)
Diffstat (limited to 'src')
-rw-r--r--src/w32.c23
-rw-r--r--src/w32proc.c17
2 files changed, 32 insertions, 8 deletions
diff --git a/src/w32.c b/src/w32.c
index e4c6d007661..cbcfcdd4f6d 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -8573,6 +8573,7 @@ int
8573sys_close (int fd) 8573sys_close (int fd)
8574{ 8574{
8575 int rc = -1; 8575 int rc = -1;
8576 bool reader_thread_exited = false;
8576 8577
8577 if (fd < 0) 8578 if (fd < 0)
8578 { 8579 {
@@ -8583,6 +8584,13 @@ sys_close (int fd)
8583 if (fd < MAXDESC && fd_info[fd].cp) 8584 if (fd < MAXDESC && fd_info[fd].cp)
8584 { 8585 {
8585 child_process * cp = fd_info[fd].cp; 8586 child_process * cp = fd_info[fd].cp;
8587 DWORD thrd_status = STILL_ACTIVE;
8588
8589 /* Thread handle will be NULL if we already called delete_child. */
8590 if (cp->thrd != NULL
8591 && GetExitCodeThread (cp->thrd, &thrd_status)
8592 && thrd_status != STILL_ACTIVE)
8593 reader_thread_exited = true;
8586 8594
8587 fd_info[fd].cp = NULL; 8595 fd_info[fd].cp = NULL;
8588 8596
@@ -8633,7 +8641,11 @@ sys_close (int fd)
8633 because socket handles are fully fledged kernel handles. */ 8641 because socket handles are fully fledged kernel handles. */
8634 if (fd < MAXDESC) 8642 if (fd < MAXDESC)
8635 { 8643 {
8636 if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0) 8644 if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0
8645 /* If the reader thread already exited, close the descriptor,
8646 since otherwise no one will close it, and we will be
8647 leaking descriptors. */
8648 || reader_thread_exited)
8637 { 8649 {
8638 fd_info[fd].flags = 0; 8650 fd_info[fd].flags = 0;
8639 rc = _close (fd); 8651 rc = _close (fd);
@@ -8641,10 +8653,11 @@ sys_close (int fd)
8641 else 8653 else
8642 { 8654 {
8643 /* We don't close here descriptors open by pipe processes 8655 /* We don't close here descriptors open by pipe processes
8644 for reading from the pipe, because the reader thread 8656 for reading from the pipe when the reader thread might
8645 might be stuck in _sys_read_ahead, and then we will hang 8657 still be running, since that thread might be stuck in
8646 here. If the reader thread exits normally, it will close 8658 _sys_read_ahead, and then we will hang here. If the
8647 the descriptor; otherwise we will leave a zombie thread 8659 reader thread exits normally, it will close the
8660 descriptor; otherwise we will leave a zombie thread
8648 hanging around. */ 8661 hanging around. */
8649 rc = 0; 8662 rc = 0;
8650 /* Leave the flag set for the reader thread to close the 8663 /* Leave the flag set for the reader thread to close the
diff --git a/src/w32proc.c b/src/w32proc.c
index 7acfba64d70..f771ebc8511 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -1287,10 +1287,21 @@ reader_thread (void *arg)
1287 } 1287 }
1288 /* If this thread was reading from a pipe process, close the 1288 /* If this thread was reading from a pipe process, close the
1289 descriptor used for reading, as sys_close doesn't in that case. */ 1289 descriptor used for reading, as sys_close doesn't in that case. */
1290 if (fd_info[fd].flags == FILE_DONT_CLOSE) 1290 if ((fd_info[fd].flags & FILE_DONT_CLOSE) == FILE_DONT_CLOSE)
1291 { 1291 {
1292 fd_info[fd].flags = 0; 1292 int i;
1293 _close (fd); 1293 /* If w32.c:sys_close is still processing this descriptor, wait
1294 for a while for it to finish. */
1295 for (i = 0; i < 5; i++)
1296 {
1297 if (fd_info[fd].flags == FILE_DONT_CLOSE)
1298 {
1299 fd_info[fd].flags = 0;
1300 _close (fd);
1301 break;
1302 }
1303 Sleep (5);
1304 }
1294 } 1305 }
1295 return 0; 1306 return 0;
1296} 1307}