zmake: wait for all logs.

This change fixes an issue that sometimes takes place. When a process
terminates prior to the stdout/stderr pipes being clear, zmake would
terminate and some of the output would be missing. This was most
repeatable in platform/ec/zephyr/test/base32.

BUG=b:176364631
TEST=zmake -l DEBUG configure --test -B ~/build/base32 \
     ../ec/zephyr/test/base32
TEST=zmake -l DEBUG testall

Change-Id: Ia99a9d600996330818a19f6a709c3e2c181ed4b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/zephyr-chrome/+/2605683
Tested-by: Yuval Peress <peress@chromium.org>
Auto-Submit: Yuval Peress <peress@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Commit-Queue: Paul Fagerburg <pfagerburg@chromium.org>
diff --git a/util/zmake/__main__.py b/util/zmake/__main__.py
index b6d8372..1eab278 100644
--- a/util/zmake/__main__.py
+++ b/util/zmake/__main__.py
@@ -9,8 +9,9 @@
 import pathlib
 import sys
 
-import zmake.zmake as zm
+import zmake.multiproc as multiproc
 import zmake.util as util
+import zmake.zmake as zm
 
 
 def call_with_namespace(func, namespace):
@@ -112,8 +113,9 @@
 
     zmake = call_with_namespace(zm.Zmake, opts)
     subcommand_method = getattr(zmake, opts.subcommand.replace('-', '_'))
-    call_with_namespace(subcommand_method, opts)
-    return 0
+    result = call_with_namespace(subcommand_method, opts)
+    multiproc.wait_for_log_end()
+    return result
 
 
 if __name__ == '__main__':
diff --git a/util/zmake/multiproc.py b/util/zmake/multiproc.py
index 48cff07..3af873e 100644
--- a/util/zmake/multiproc.py
+++ b/util/zmake/multiproc.py
@@ -36,11 +36,13 @@
         logger, log_level = _logging_map[fd]
         if fd.closed:
             del _logging_map[fd]
+            _logging_cv.notify_all()
             return
         line = fd.readline()
         if not line:
             # EOF
             del _logging_map[fd]
+            _logging_cv.notify_all()
             return
         line = line.strip()
         if line:
@@ -57,6 +59,8 @@
         remove = [fd for fd in _logging_map.keys() if fd.closed]
         for fd in remove:
             del _logging_map[fd]
+        if remove:
+            _logging_cv.notify_all()
 
 
 def _logging_loop():
@@ -113,6 +117,15 @@
         _logging_cv.notify_all()
 
 
+def wait_for_log_end():
+    """Wait for all the logs to be printed.
+
+    This method will block execution until all the logs have been flushed out.
+    """
+    with _logging_cv:
+        _logging_cv.wait_for(lambda: not _logging_map)
+
+
 class Executor:
     """Parallel executor helper class.