commit:     7b5bbf0c24eeb3fb64c4797905595401b8aa2731
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Jul 29 04:30:06 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Aug  9 00:23:47 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=7b5bbf0c

BuildLogger: fix _cancel to cleanup PipeLogger quickly

Cleanup PipeLogger as quickly as possible, in order to prevent
access to unclosed logs.

Bug: https://bugs.gentoo.org/711174
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/portage/util/_async/BuildLogger.py | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/lib/portage/util/_async/BuildLogger.py 
b/lib/portage/util/_async/BuildLogger.py
index 20362cf6b..f25f70d5b 100644
--- a/lib/portage/util/_async/BuildLogger.py
+++ b/lib/portage/util/_async/BuildLogger.py
@@ -1,6 +1,7 @@
 # Copyright 2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
+import functools
 import subprocess
 
 from _emerge.AsynchronousTask import AsynchronousTask
@@ -23,7 +24,7 @@ class BuildLogger(AsynchronousTask):
        subprocess stdout and stderr streams).
        """
 
-       __slots__ = ('env', 'log_path', 'log_filter_file', '_main_task', 
'_stdin')
+       __slots__ = ('env', 'log_path', 'log_filter_file', '_main_task', 
'_main_task_cancel', '_stdin')
 
        @property
        def stdin(self):
@@ -76,6 +77,7 @@ class BuildLogger(AsynchronousTask):
                        log_file_path=self.log_path)
                pipe_logger.start()
 
+               self._main_task_cancel = functools.partial(self._main_cancel, 
filter_proc, pipe_logger)
                self._main_task = asyncio.ensure_future(self._main(filter_proc, 
pipe_logger), loop=self.scheduler)
                self._main_task.add_done_callback(self._main_exit)
 
@@ -87,19 +89,28 @@ class BuildLogger(AsynchronousTask):
                        if filter_proc is not None and filter_proc.poll() is 
None:
                                yield filter_proc.async_wait()
                except asyncio.CancelledError:
-                       if pipe_logger.poll() is None:
-                               pipe_logger.cancel()
-                       if filter_proc is not None and filter_proc.poll() is 
None:
-                               filter_proc.cancel()
+                       self._main_cancel(filter_proc, pipe_logger)
                        raise
 
+       def _main_cancel(self, filter_proc, pipe_logger):
+               if pipe_logger.poll() is None:
+                       pipe_logger.cancel()
+               if filter_proc is not None and filter_proc.poll() is None:
+                       filter_proc.cancel()
+
        def _cancel(self):
                if self._main_task is not None:
-                       self._main_task.done() or self._main_task.cancel()
+                       if not self._main_task.done():
+                               if self._main_task_cancel is not None:
+                                       self._main_task_cancel()
+                                       self._main_task_cancel = None
+                               self._main_task.cancel()
                if self._stdin is not None and not self._stdin.closed:
                        self._stdin.close()
 
        def _main_exit(self, main_task):
+               self._main_task = None
+               self._main_task_cancel = None
                try:
                        main_task.result()
                except asyncio.CancelledError:

Reply via email to