Ejemplo n.º 1
0
def test_wait_for_objects():
    long_cmd = [sys.executable, "-c", "import time; time.sleep(40.0)"]
    short_cmd = [sys.executable, "-c", "pass"]

    p = e3.os.process.Run(long_cmd, bg=True)

    assert (wait_for_objects([int(p.internal._handle)], timeout=1) is
            None), "timeout was expected"
    p.kill()

    p0 = e3.os.process.Run(long_cmd, bg=True)
    p1 = e3.os.process.Run(short_cmd, bg=True)

    try:
        assert (wait_for_objects(
            [int(p0.internal._handle),
             int(p1.internal._handle)],
            timeout=2) == 1), "process 1 was expected"
    finally:
        p0.kill()
        p1.kill()

    p0 = e3.os.process.Run(long_cmd, bg=True)
    p1 = e3.os.process.Run(short_cmd, bg=True)

    try:
        assert (wait_for_objects(
            [int(p0.internal._handle),
             int(p1.internal._handle)],
            timeout=2,
            wait_for_all=True,
        ) is None), "timeout expected"
    finally:
        p0.kill()
        p1.kill()

    p0 = e3.os.process.Run(short_cmd, bg=True)
    p1 = e3.os.process.Run(short_cmd, bg=True)
    try:
        assert (wait_for_objects(
            [int(p0.internal._handle),
             int(p1.internal._handle)],
            timeout=0,
            wait_for_all=True,
        ) is not None), "no timeout expected"
    finally:
        p0.kill()
        p1.kill()
Ejemplo n.º 2
0
def wait_for_processes(process_list, timeout):
    """Wait for several processes spawned with Run.

    :param process_list: a list of Run objects
    :type process_list: list[Run]
    :param timeout: a timeout in seconds. If 0 block until a process ends.
    :type timeout: int

    :return: None in case of timeout or the index in process Run corresponding
        to the first process that end
    :rtype: None | int
    """
    if len(process_list) == 0:
        return None

    start = time.time()
    remain = timeout

    if sys.platform == 'win32':  # unix: no cover
        from e3.os.windows.process import process_exit_code, wait_for_objects

        handles = [int(p.internal._handle) for p in process_list]

        while True:
            try:
                idx = wait_for_objects(handles, remain, False)
                if idx is None:
                    return

                if process_exit_code(handles[idx]) is None:
                    # Process is still active so wait after updating timeout
                    remain = timeout - time.time() + start

                    if remain <= 0:
                        # No remaining time
                        return None
                else:
                    # Process is exiting so finalize it by calling wait
                    process_list[idx].wait()
                    return idx
            except OSError:
                raise WaitError

    else:  # windows: no cover
        import select

        # Each time a SIGCHLD signal is received write into pipe. Use
        # then select which support timeout arguments to wait.
        fd_r, fd_w = os.pipe()

        def handler(signum, frame):
            del signum, frame
            os.write(fd_w, b'a')

        signal.signal(signal.SIGCHLD, handler)

        try:
            while remain >= 0.0 or timeout == 0:
                # Do a first check in case a SIGCHLD was emited before the
                # initialisation of the handler.
                for index, p in enumerate(process_list):
                    if p.poll() is not None:
                        return index

                # Wait for a sigchld signal. Note that select might
                # be interrupted by signals thus the loop
                select_args = [[fd_r], [], []]
                if timeout != 0:
                    select_args.append(remain)

                while True:
                    try:
                        l_r, _, _ = select.select(*select_args)
                        if l_r:
                            os.read(fd_r, 1)
                        break
                    except select.error:
                        pass

                remain = timeout - time.time() + start

            logger.warning('no process ended after %f seconds',
                           time.time() - start)  # defensive code

        finally:
            # Be sure to remove signal handler and close pipe
            signal.signal(signal.SIGCHLD, 0)
            os.close(fd_r)
            os.close(fd_w)
Ejemplo n.º 3
0
def wait_for_processes(process_list, timeout):
    """Wait for several processes spawned with Run.

    :param process_list: a list of Run objects
    :type process_list: list[Run]
    :param timeout: a timeout in seconds. If 0 block until a process ends.
    :type timeout: int

    :return: None in case of timeout or the index in process Run corresponding
        to the first process that end
    :rtype: None | int
    """
    if len(process_list) == 0:
        return None

    start = time.time()
    remain = timeout

    if sys.platform == 'win32':  # unix: no cover
        from e3.os.windows.process import process_exit_code, wait_for_objects

        handles = [int(p.internal._handle) for p in process_list]

        while True:
            try:
                idx = wait_for_objects(handles, remain, False)
                if idx is None:
                    return

                if process_exit_code(handles[idx]) is None:
                    # Process is still active so wait after updating timeout
                    remain = timeout - time.time() + start

                    if remain <= 0:
                        # No remaining time
                        return None
                else:
                    # Process is exiting so finalize it by calling wait
                    process_list[idx].wait()
                    return idx
            except OSError:
                raise WaitError

    else:
        import e3.os.unix.process
        # Choose between blocking or non-blocking call to wait
        blocking = True
        if timeout != 0:
            blocking = False

        while remain >= 0.0 or timeout == 0:
            # Retrieve first child process that ends. Note that that child
            # process might not be in our watch list
            pid = e3.os.unix.process.wait(blocking)

            if pid != 0:
                # We have a result
                result = next((index for index, p in
                               enumerate(process_list) if p.pid == pid), None)
                if result is not None:
                    # At the stage we need to set the process status and close
                    # related handles. Indeed we will not be able to use the
                    # wait method afterwards and retrieve it.
                    process_list[result].wait()
                    return result
            time.sleep(1.0)
            remain = timeout - time.time() + start
        return None