'Performs the given action with a timeout.
The action must be non-blocking, and raise an instance of exc on a
recoverable failure.  If the action fails with an instance of exc,
we wait on wait_cond before trying again.  Failure after the
timeout is reached is propagated as an exception.  Success is
signalled by notifying on done_cond and returning the result of
the action.  If action raises any exception besides an instance of
exc, it is immediately propagated.
Args:
action: A callable that performs a non-blocking action.
exc: An exception type that is thrown by the action to indicate
a recoverable error.
wait_cond: A condition variable which should be waited on when
action throws exc.
done_cond: A condition variable to signal if the action returns.
lock: The lock used by wait_cond and done_cond.
timeout: A non-negative float indicating the maximum time to wait.
block: Whether to block if the action cannot complete immediately.
Returns:
The result of the action, if it is successful.
Raises:
ValueError: If the timeout argument is negative.'

def _DoWithTimeout(self, action, exc, wait_cond, done_cond, lock, timeout=None, block=True):

    if ((timeout is not None) and (timeout < 0.0)):
        raise ValueError("'timeout'    must    not    be    a    negative        number")
    if (not block):
        timeout = 0.0
    result = None
    success = False
    start_time = self.get_time()
    lock.acquire()
    try:
        while (not success):
            try:
                result = action()
                success = True
            except Exception as e:
                if (not isinstance(e, exc)):
                    raise e
                if (timeout is not None):
                    elapsed_time = (self.get_time() - start_time)
                    timeout -= elapsed_time
                    if (timeout <= 0.0):
                        raise e
                wait_cond.wait(timeout)
    finally:
        if success:
            done_cond.notify()
        lock.release()
    return result
