process: Early return during process termination if no proc running

This avoids extra unneeded logging about killing with signal when
actually no signal is being sent.

Change-Id: I5b5dd78fe3301d8eef2ab93da3b37029268ae198
diff --git a/selftest/suite_test.ok b/selftest/suite_test.ok
index 85e94b2..908f24f 100644
--- a/selftest/suite_test.ok
+++ b/selftest/suite_test.ok
@@ -96,14 +96,6 @@
 tst hello_world.py:[LINENR]: two  [test_suite↪hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR]: three  [test_suite↪hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR] Test passed (N.N sec)  [test_suite↪hello_world.py]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL
 ---------------------------------------------------------------------
 trial test_suite PASS
 ---------------------------------------------------------------------
@@ -127,14 +119,6 @@
 tst test_error.py:[LINENR]: I am 'test_suite' / 'test_error.py:[LINENR]'  [test_suite↪test_error.py:[LINENR]]  [test_error.py:[LINENR]]
 tst test_error.py:[LINENR]: ERR: AssertionError: test_error.py:[LINENR]: assert False  [test_suite↪test_error.py:[LINENR]]  [test_error.py:[LINENR]: assert False]
 tst test_error.py:[LINENR]: Test FAILED (N.N sec)  [test_suite↪test_error.py:[LINENR]]  [test.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
 ---------------------------------------------------------------------
 trial test_suite FAIL
 ---------------------------------------------------------------------
@@ -158,14 +142,6 @@
 tst test_fail.py:[LINENR]: I am 'test_suite' / 'test_fail.py:[LINENR]'  [test_suite↪test_fail.py:[LINENR]]  [test_fail.py:[LINENR]]
 tst test_fail.py:[LINENR]: ERR: EpicFail: This failure is expected  [test_suite↪test_fail.py:[LINENR]]  [test_fail.py:[LINENR]]
 tst test_fail.py:[LINENR]: Test FAILED (N.N sec)  [test_suite↪test_fail.py:[LINENR]]  [test.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
 ---------------------------------------------------------------------
 trial test_suite FAIL
 ---------------------------------------------------------------------
@@ -188,14 +164,6 @@
 ----------------------------------------------
 tst test_fail_raise.py:[LINENR]: ERR: ExpectedFail: This failure is expected  [test_suite↪test_fail_raise.py:[LINENR]]  [test_fail_raise.py:[LINENR]: raise ExpectedFail('This failure is expected')]
 tst test_fail_raise.py:[LINENR]: Test FAILED (N.N sec)  [test_suite↪test_fail_raise.py:[LINENR]]  [test.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
 ---------------------------------------------------------------------
 trial test_suite FAIL
 ---------------------------------------------------------------------
@@ -283,14 +251,6 @@
 tst hello_world.py:[LINENR]: two  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR]: three  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR] Test passed (N.N sec)  [test_suite↪hello_world.py]  [test.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
 ---------------------------------------------------------------------
 trial test_suite PASS
 ---------------------------------------------------------------------
@@ -378,14 +338,6 @@
 tst hello_world.py:[LINENR]: two  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR]: three  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR] Test passed (N.N sec)  [test_suite↪hello_world.py]  [test.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
 ---------------------------------------------------------------------
 trial test_suite PASS
 ---------------------------------------------------------------------
@@ -519,14 +471,6 @@
 tst hello_world.py:[LINENR]: two  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR]: three  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]
 tst hello_world.py:[LINENR] Test passed (N.N sec)  [test_suite↪hello_world.py]  [test.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Scheduled to terminate 0 processes.  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGTERM  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGINT  [process.py:[LINENR]]
---- ParallelTerminationStrategy: DBG: Starting to kill with SIGKILL  [process.py:[LINENR]]
 ---------------------------------------------------------------------
 trial test_suite PASS
 ---------------------------------------------------------------------
diff --git a/src/osmo_gsm_tester/process.py b/src/osmo_gsm_tester/process.py
index 441d4ea..66ecae5 100644
--- a/src/osmo_gsm_tester/process.py
+++ b/src/osmo_gsm_tester/process.py
@@ -104,7 +104,10 @@
             time.sleep(wait_step)
 
     def terminate_all(self):
-        self.dbg("Scheduled to terminate %d processes." % len(self._processes))
+        num_processes = len(self._processes)
+        self.dbg("Scheduled to terminate %d processes." % num_processes)
+        if num_processes == 0:
+            return
         self._prune_dead_processes(True)
         self._build_process_map()
 
@@ -116,6 +119,8 @@
             if sig == signal.SIGKILL:
                 continue
             self._poll_for_termination()
+            if len(self._processes) == 0:
+                return
 
 
 class Process(log.Origin):
diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py
index 85eca46..0738e96 100644
--- a/src/osmo_gsm_tester/suite.py
+++ b/src/osmo_gsm_tester/suite.py
@@ -244,6 +244,8 @@
         self._processes.insert(0, (process, respawn))
 
     def stop_processes(self):
+        if len(self._processes) == 0:
+            return
         strategy = process.ParallelTerminationStrategy()
         while self._processes:
             proc, _ = self._processes.pop()