Windows: fix termination of process output redirection (#29923)
The parent thread in the process stdout redirection logic on Windows was closing a file that was being read in child thread, which lead to error-based termination of the reader thread. This updates the interaction to avoid the error.
This commit is contained in:
		@@ -809,19 +809,23 @@ def __enter__(self):
 | 
				
			|||||||
            def background_reader(reader, echo_writer, _kill):
 | 
					            def background_reader(reader, echo_writer, _kill):
 | 
				
			||||||
                # for each line printed to logfile, read it
 | 
					                # for each line printed to logfile, read it
 | 
				
			||||||
                # if echo: write line to user
 | 
					                # if echo: write line to user
 | 
				
			||||||
                while True:
 | 
					                try:
 | 
				
			||||||
                    is_killed = _kill.wait(.1)
 | 
					                    while True:
 | 
				
			||||||
                    self.stderr.flush()
 | 
					                        is_killed = _kill.wait(.1)
 | 
				
			||||||
                    self.stdout.flush()
 | 
					                        # Flush buffered build output to file
 | 
				
			||||||
                    line = reader.readline()
 | 
					                        # stdout/err fds refer to log file
 | 
				
			||||||
                    while line:
 | 
					                        self.stderr.flush()
 | 
				
			||||||
                        if self.echo:
 | 
					                        self.stdout.flush()
 | 
				
			||||||
                            self.echo_writer.write('{0}'.format(line.decode()))
 | 
					 | 
				
			||||||
                            self.echo_writer.flush()
 | 
					 | 
				
			||||||
                        line = reader.readline()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if is_killed:
 | 
					                        line = reader.readline()
 | 
				
			||||||
                        break
 | 
					                        if self.echo and line:
 | 
				
			||||||
 | 
					                            echo_writer.write('{0}'.format(line.decode()))
 | 
				
			||||||
 | 
					                            echo_writer.flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if is_killed:
 | 
				
			||||||
 | 
					                            break
 | 
				
			||||||
 | 
					                finally:
 | 
				
			||||||
 | 
					                    reader.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._active = True
 | 
					            self._active = True
 | 
				
			||||||
            with replace_environment(self.env):
 | 
					            with replace_environment(self.env):
 | 
				
			||||||
@@ -837,7 +841,6 @@ def __exit__(self, exc_type, exc_val, exc_tb):
 | 
				
			|||||||
            self._ioflag = False
 | 
					            self._ioflag = False
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.writer.close()
 | 
					            self.writer.close()
 | 
				
			||||||
            self.reader.close()
 | 
					 | 
				
			||||||
            self.echo_writer.flush()
 | 
					            self.echo_writer.flush()
 | 
				
			||||||
            self.stdout.flush()
 | 
					            self.stdout.flush()
 | 
				
			||||||
            self.stderr.flush()
 | 
					            self.stderr.flush()
 | 
				
			||||||
@@ -853,10 +856,7 @@ def force_echo(self):
 | 
				
			|||||||
        if not self._active:
 | 
					        if not self._active:
 | 
				
			||||||
            raise RuntimeError(
 | 
					            raise RuntimeError(
 | 
				
			||||||
                "Can't call force_echo() outside log_output region!")
 | 
					                "Can't call force_echo() outside log_output region!")
 | 
				
			||||||
        try:
 | 
					        yield
 | 
				
			||||||
            yield self
 | 
					 | 
				
			||||||
        finally:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo,
 | 
					def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@
 | 
				
			|||||||
import llnl.util.tty as tty
 | 
					import llnl.util.tty as tty
 | 
				
			||||||
import llnl.util.tty.colify
 | 
					import llnl.util.tty.colify
 | 
				
			||||||
import llnl.util.tty.color as color
 | 
					import llnl.util.tty.color as color
 | 
				
			||||||
from llnl.util.tty.log import log_output, winlog
 | 
					from llnl.util.tty.log import log_output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import spack
 | 
					import spack
 | 
				
			||||||
import spack.cmd
 | 
					import spack.cmd
 | 
				
			||||||
@@ -605,14 +605,9 @@ def __call__(self, *argv, **kwargs):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        out = StringIO()
 | 
					        out = StringIO()
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if sys.platform == 'win32':
 | 
					            with log_output(out):
 | 
				
			||||||
                with winlog(out):
 | 
					                self.returncode = _invoke_command(
 | 
				
			||||||
                    self.returncode = _invoke_command(
 | 
					                    self.command, self.parser, args, unknown)
 | 
				
			||||||
                        self.command, self.parser, args, unknown)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                with log_output(out):
 | 
					 | 
				
			||||||
                    self.returncode = _invoke_command(
 | 
					 | 
				
			||||||
                        self.command, self.parser, args, unknown)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        except SystemExit as e:
 | 
					        except SystemExit as e:
 | 
				
			||||||
            self.returncode = e.code
 | 
					            self.returncode = e.code
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user