Beispiel #1
0
    def test__count(self):
        # Test the _count() function.
        orig = thread._count()
        mut = thread.allocate_lock()
        mut.acquire()
        started = []

        def task():
            started.append(None)
            mut.acquire()
            mut.release()

        with threading_helper.wait_threads_exit():
            thread.start_new_thread(task, ())
            for _ in support.sleeping_retry(support.LONG_TIMEOUT):
                if started:
                    break
            self.assertEqual(thread._count(), orig + 1)

            # Allow the task to finish.
            mut.release()

            # The only reliable way to be sure that the thread ended from the
            # interpreter's point of view is to wait for the function object to
            # be destroyed.
            done = []
            wr = weakref.ref(task, lambda _: done.append(None))
            del task

            for _ in support.sleeping_retry(support.LONG_TIMEOUT):
                if done:
                    break
                support.gc_collect()  # For PyPy or other GCs.
            self.assertEqual(thread._count(), orig)
Beispiel #2
0
def wait_threads_exit(timeout=None):
    """
    bpo-31234: Context manager to wait until all threads created in the with
    statement exit.

    Use _thread.count() to check if threads exited. Indirectly, wait until
    threads exit the internal t_bootstrap() C function of the _thread module.

    threading_setup() and threading_cleanup() are designed to emit a warning
    if a test leaves running threads in the background. This context manager
    is designed to cleanup threads started by the _thread.start_new_thread()
    which doesn't allow to wait for thread exit, whereas thread.Thread has a
    join() method.
    """
    if timeout is None:
        timeout = support.SHORT_TIMEOUT
    old_count = _thread._count()
    try:
        yield
    finally:
        start_time = time.monotonic()
        for _ in support.sleeping_retry(timeout, error=False):
            support.gc_collect()
            count = _thread._count()
            if count <= old_count:
                break
        else:
            dt = time.monotonic() - start_time
            msg = (f"wait_threads() failed to cleanup {count - old_count} "
                   f"threads after {dt:.1f} seconds "
                   f"(count: {count}, old count: {old_count})")
            raise AssertionError(msg)
Beispiel #3
0
    def test_wait(self):
        for i in range(NUM_THREADS):
            thread = threading.Thread(target=self.f, args=(i, ))
            thread.start()
            self.threads.append(thread)

        # busy-loop to wait for threads
        for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
            if len(self.alive) >= NUM_THREADS:
                break

        a = sorted(self.alive.keys())
        self.assertEqual(a, list(range(NUM_THREADS)))

        prefork_lives = self.alive.copy()

        if sys.platform in ['unixware7']:
            cpid = os.fork1()
        else:
            cpid = os.fork()

        if cpid == 0:
            # Child
            time.sleep(LONGSLEEP)
            n = 0
            for key in self.alive:
                if self.alive[key] != prefork_lives[key]:
                    n += 1
            os._exit(n)
        else:
            # Parent
            self.wait_impl(cpid, exitcode=0)
Beispiel #4
0
    def _lock(self, lock_func, lock_name):
        self.addCleanup(os_helper.unlink, os_helper.TESTFN)
        code = '\n'.join(("import fcntl, time",
                          "with open('%s', 'wb') as f:" % os_helper.TESTFN,
                          "   fcntl.%s(f, fcntl.LOCK_EX)" % lock_name,
                          "   time.sleep(%s)" % self.sleep_time))
        start_time = time.monotonic()
        proc = self.subprocess(code)
        with kill_on_error(proc):
            with open(os_helper.TESTFN, 'wb') as f:
                # synchronize the subprocess
                start_time = time.monotonic()
                for _ in support.sleeping_retry(support.LONG_TIMEOUT,
                                                error=False):
                    try:
                        lock_func(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
                        lock_func(f, fcntl.LOCK_UN)
                    except BlockingIOError:
                        break
                else:
                    dt = time.monotonic() - start_time
                    raise Exception("failed to sync child in %.1f sec" % dt)

                # the child locked the file just a moment ago for 'sleep_time' seconds
                # that means that the lock below will block for 'sleep_time' minus some
                # potential context switch delay
                lock_func(f, fcntl.LOCK_EX)
                dt = time.monotonic() - start_time
                self.assertGreaterEqual(dt, self.sleep_time)
                self.stop_alarm()
            proc.wait()
Beispiel #5
0
    def wait_impl(self, cpid, *, exitcode):
        # This many iterations can be required, since some previously run
        # tests (e.g. test_ctypes) could have spawned a lot of children
        # very quickly.
        for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
            # wait3() shouldn't hang, but some of the buildbots seem to hang
            # in the forking tests.  This is an attempt to fix the problem.
            spid, status, rusage = os.wait3(os.WNOHANG)
            if spid == cpid:
                break

        self.assertEqual(spid, cpid)
        self.assertEqual(os.waitstatus_to_exitcode(status), exitcode)
        self.assertTrue(rusage)
Beispiel #6
0
 def wait_impl(self, cpid, *, exitcode):
     option = os.WNOHANG
     if sys.platform.startswith('aix'):
         # Issue #11185: wait4 is broken on AIX and will always return 0
         # with WNOHANG.
         option = 0
     for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
         # wait4() shouldn't hang, but some of the buildbots seem to hang
         # in the forking tests.  This is an attempt to fix the problem.
         spid, status, rusage = os.wait4(cpid, option)
         if spid == cpid:
             break
     self.assertEqual(spid, cpid)
     self.assertEqual(os.waitstatus_to_exitcode(status), exitcode)
     self.assertTrue(rusage)