pw_unit_test: Add test runner pool

Adds a pw_unit_test test runner pool to allow targets to individually
limit maxium test runner concurrency.

Change-Id: Ieaf240bbd7dbdb0a811eb11047c6e2a29e2e5197
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/72740
Reviewed-by: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_unit_test/test.gni b/pw_unit_test/test.gni
index fc112cf..966bd45 100644
--- a/pw_unit_test/test.gni
+++ b/pw_unit_test/test.gni
@@ -20,20 +20,54 @@
 declare_args() {
   # Path to a test runner to automatically run unit tests after they are built.
   #
-  # If set, the pw_test() template creates an action that invokes the test runner
-  # on each test executable. If unset, the pw_test() template only creates a test
-  # executable target.
+  # If set, a ``pw_test`` target's ``<target_name>.run`` action will invoke the
+  # test runner specified by this argument, passing the path to the unit test to
+  # run. If this is unset, the ``pw_test`` target's ``<target_name>.run`` step
+  # will do nothing.
   #
-  # This should only be enabled for targets which support parallelized running of
-  # unit tests, such as desktops with multiple cores.
+  # Targets that don't support parallelized execution of tests (e.g. a on-device
+  # test runner that must flash a device and run the test in serial) should
+  # set pw_unit_test_POOL_DEPTH to 1.
+  #
+  # Type: string (name of an executable on the PATH, or path to an executable)
+  # Usage: toolchain-controlled only
   pw_unit_test_AUTOMATIC_RUNNER = ""
 
   # Additional dependencies required by all unit test targets. (For example, if
   # using a different test library like Googletest.)
+  #
+  # Type: list of strings (list of dependencies as GN paths)
+  # Usage: toolchain-controlled only
   pw_unit_test_PUBLIC_DEPS = []
 
-  # Implementation of a main function for "pw_test" unit test binaries.
+  # Implementation of a main function for ``pw_test`` unit test binaries.
+  #
+  # Type: string (GN path to a source set)
+  # Usage: toolchain-controlled only
   pw_unit_test_MAIN = "$dir_pw_unit_test:simple_printing_main"
+
+  # The maximum number of unit tests that may be run concurrently for the
+  # current toolchain. Setting this to 0 disables usage of a pool, allowing
+  # unlimited parallelization.
+  #
+  # Note: A single target with two toolchain configurations (e.g. release/debug)
+  #       will use two separate test runner pools by default. Set
+  #       pw_unit_test_POOL_TOOLCHAIN to the same toolchain for both targets to
+  #       merge the pools and force serialization.
+  #
+  # Type: integer
+  # Usage: toolchain-controlled only
+  pw_unit_test_POOL_DEPTH = 0
+
+  # The toolchain to use when referring to the pw_unit_test runner pool. When
+  # this is disabled, the current toolchain is used. This means that every
+  # toolchain will use its own pool definition. If two toolchains should share
+  # the same pool, this argument should be by one of the toolchains to the GN
+  # path of the other toolchain.
+  #
+  # Type: string (GN path to a toolchain)
+  # Usage: toolchain-controlled only
+  pw_unit_test_POOL_TOOLCHAIN = ""
 }
 
 # Defines a target if enable_if is true. Otherwise, it defines that target as
@@ -179,6 +213,15 @@
     }
 
     pw_python_action(_test_to_run + ".run") {
+      # Optionally limit max test runner concurrency.
+      if (pw_unit_test_POOL_DEPTH != 0) {
+        _pool_toolchain = current_toolchain
+        if (pw_unit_test_POOL_TOOLCHAIN != "") {
+          _pool_toolchain = pw_unit_test_POOL_TOOLCHAIN
+        }
+        pool = "$dir_pw_unit_test:unit_test_pool($_pool_toolchain)"
+      }
+
       deps = [ ":$_test_target_name" ]
       inputs = [ pw_unit_test_AUTOMATIC_RUNNER ]
       script = "$dir_pw_unit_test/py/pw_unit_test/test_runner.py"