Support early exit from wait_until_keyword_succeeds in wait_state

Currently, wait_until_keyword_succeeds() doesn't provide a means for a
programmer to exit early for a special condition.

This commit contains a solution whereby a signal handler can be invoked
to set a global wait_early_exit_message to indicate to check_state and
wait_state that an early exit should be made and it should count as a
failure.

Change-Id: Ieff03d76aa2d8908e22cc13b23f3c7609ab0b674
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/lib/state.py b/lib/state.py
index 7cdcb8c..298c686 100755
--- a/lib/state.py
+++ b/lib/state.py
@@ -619,6 +619,25 @@
     return state
 
 
+exit_wait_early_message = ""
+
+
+def set_exit_wait_early_message(value):
+    r"""
+    Set global exit_wait_early_message to the indicated value.
+
+    This is a mechanism by which the programmer can do an early exit from
+    wait_until_keyword_succeeds() based on some special condition.
+
+    Description of argument(s):
+    value                           The value to assign to the global
+                                    exit_wait_early_message.
+    """
+
+    global exit_wait_early_message
+    exit_wait_early_message = value
+
+
 def check_state(match_state,
                 invert=0,
                 print_string="",
@@ -680,6 +699,13 @@
     if not quiet:
         gp.print_var(state)
 
+    if exit_wait_early_message != "":
+        # The exit_wait_early_message has been set by a signal handler so we
+        # will exit "successfully".  It is incumbent upon the calling function
+        # (e.g. wait_state) to check/clear this variable and to fail
+        # appropriately.
+        return state
+
     match = compare_states(state, match_state)
 
     if invert and match:
@@ -786,6 +812,14 @@
         message = my_assertion_error.args[0]
         BuiltIn().fail(message)
 
+    if exit_wait_early_message:
+        # The global exit_wait_early_message was set by a signal handler
+        # indicating that we should fail.
+        message = exit_wait_early_message
+        # Clear the exit_wait_early_message variable for future use.
+        set_exit_wait_early_message("")
+        BuiltIn().fail(gp.sprint_error(message))
+
     if not quiet:
         gp.printn()
         if invert: