Ejemplo n.º 1
0
    def test_signals(self):
        with threading_helper.wait_threads_exit():
            # Test signal handling semantics of threads.
            # We spawn a thread, have the thread send two signals, and
            # wait for it to finish. Check that we got both signals
            # and that they were run by the main thread.
            signalled_all.acquire()
            self.spawnSignallingThread()
            signalled_all.acquire()

        # the signals that we asked the kernel to send
        # will come back, but we don't know when.
        # (it might even be after the thread exits
        # and might be out of order.)  If we haven't seen
        # the signals yet, send yet another signal and
        # wait for it return.
        if signal_blackboard[signal.SIGUSR1]['tripped'] == 0 \
           or signal_blackboard[signal.SIGUSR2]['tripped'] == 0:
            try:
                signal.alarm(1)
                signal.pause()
            finally:
                signal.alarm(0)

        self.assertEqual(signal_blackboard[signal.SIGUSR1]['tripped'], 1)
        self.assertEqual(signal_blackboard[signal.SIGUSR1]['tripped_by'],
                         thread.get_ident())
        self.assertEqual(signal_blackboard[signal.SIGUSR2]['tripped'], 1)
        self.assertEqual(signal_blackboard[signal.SIGUSR2]['tripped_by'],
                         thread.get_ident())
        signalled_all.release()
Ejemplo n.º 2
0
    def acquire_retries_on_intr(self, lock):
        self.sig_recvd = False

        def my_handler(signal, frame):
            self.sig_recvd = True

        old_handler = signal.signal(signal.SIGUSR1, my_handler)
        try:

            def other_thread():
                # Acquire the lock in a non-main thread, so this test works for
                # RLocks.
                lock.acquire()
                # Wait until the main thread is blocked in the lock acquire, and
                # then wake it up with this.
                time.sleep(0.5)
                os.kill(process_pid, signal.SIGUSR1)
                # Let the main thread take the interrupt, handle it, and retry
                # the lock acquisition.  Then we'll let it run.
                time.sleep(0.5)
                lock.release()

            with threading_helper.wait_threads_exit():
                thread.start_new_thread(other_thread, ())
                # Wait until we can't acquire it without blocking...
                while lock.acquire(blocking=False):
                    lock.release()
                    time.sleep(0.01)
                result = lock.acquire()  # Block while we receive a signal.
                self.assertTrue(self.sig_recvd)
                self.assertTrue(result)
        finally:
            signal.signal(signal.SIGUSR1, old_handler)
Ejemplo n.º 3
0
    def test_nt_and_posix_stack_size(self):
        try:
            thread.stack_size(4096)
        except ValueError:
            verbose_print("caught expected ValueError setting "
                          "stack_size(4096)")
        except thread.error:
            self.skipTest("platform does not support changing thread stack "
                          "size")

        fail_msg = "stack_size(%d) failed - should succeed"
        for tss in (262144, 0x100000, 0):
            thread.stack_size(tss)
            self.assertEqual(thread.stack_size(), tss, fail_msg % tss)
            verbose_print("successfully set stack_size(%d)" % tss)

        for tss in (262144, 0x100000):
            verbose_print("trying stack_size = (%d)" % tss)
            self.next_ident = 0
            self.created = 0
            with threading_helper.wait_threads_exit():
                for i in range(NUMTASKS):
                    self.newtask()

                verbose_print("waiting for all tasks to complete")
                self.done_mutex.acquire()
                verbose_print("all tasks done")

        thread.stack_size(0)
Ejemplo n.º 4
0
    def test_rlock_acquire_interruption(self):
        # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck
        # in a deadlock.
        # XXX this test can fail when the legacy (non-semaphore) implementation
        # of locks is used in thread_pthread.h, see issue #11223.
        oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt)
        try:
            rlock = thread.RLock()

            # For reentrant locks, the initial acquisition must be in another
            # thread.
            def other_thread():
                rlock.acquire()

            with threading_helper.wait_threads_exit():
                thread.start_new_thread(other_thread, ())
                # Wait until we can't acquire it without blocking...
                while rlock.acquire(blocking=False):
                    rlock.release()
                    time.sleep(0.01)
                signal.alarm(1)
                t1 = time.monotonic()
                self.assertRaises(KeyboardInterrupt, rlock.acquire, timeout=5)
                dt = time.monotonic() - t1
                # See rationale above in test_lock_acquire_interruption
                self.assertLess(dt, 3.0)
        finally:
            signal.alarm(0)
            signal.signal(signal.SIGALRM, oldalrm)
Ejemplo n.º 5
0
    def test_forkinthread(self):
        pid = None

        def fork_thread(read_fd, write_fd):
            nonlocal pid

            # fork in a thread
            pid = os.fork()
            if pid:
                # parent process
                return

            # child process
            try:
                os.close(read_fd)
                os.write(write_fd, b"OK")
            finally:
                os._exit(0)

        with threading_helper.wait_threads_exit():
            thread.start_new_thread(fork_thread, (self.read_fd, self.write_fd))
            self.assertEqual(os.read(self.read_fd, 2), b"OK")
            os.close(self.write_fd)

        self.assertIsNotNone(pid)
        support.wait_process(pid, exitcode=0)
Ejemplo n.º 6
0
    def __init__(self, f, n, wait_before_exit=False):
        """
        Construct a bunch of `n` threads running the same function `f`.
        If `wait_before_exit` is True, the threads won't terminate until
        do_finish() is called.
        """
        self.f = f
        self.n = n
        self.started = []
        self.finished = []
        self._can_exit = not wait_before_exit
        self.wait_thread = threading_helper.wait_threads_exit()
        self.wait_thread.__enter__()

        def task():
            tid = threading.get_ident()
            self.started.append(tid)
            try:
                f()
            finally:
                self.finished.append(tid)
                while not self._can_exit:
                    _wait()

        try:
            for i in range(n):
                start_new_thread(task, ())
        except:
            self._can_exit = True
            raise
Ejemplo n.º 7
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, ())
            while not started:
                time.sleep(POLL_SLEEP)
            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
            while not done:
                time.sleep(POLL_SLEEP)
            self.assertEqual(thread._count(), orig)
Ejemplo n.º 8
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)
Ejemplo n.º 9
0
    def test_forkinthread(self):
        status = "not set"

        def thread1():
            nonlocal status

            # fork in a thread
            pid = os.fork()
            if pid == 0:
                # child
                try:
                    os.close(self.read_fd)
                    os.write(self.write_fd, b"OK")
                finally:
                    os._exit(0)
            else:
                # parent
                os.close(self.write_fd)
                pid, status = os.waitpid(pid, 0)

        with threading_helper.wait_threads_exit():
            thread.start_new_thread(thread1, ())
            self.assertEqual(os.read(self.read_fd, 2), b"OK",
                             "Unable to fork() in thread")
        self.assertEqual(status, 0)
Ejemplo n.º 10
0
 def test_starting_threads(self):
     with threading_helper.wait_threads_exit():
         # Basic test for thread creation.
         for i in range(NUMTASKS):
             self.newtask()
         verbose_print("waiting for tasks to complete...")
         self.done_mutex.acquire()
         verbose_print("all tasks done")
Ejemplo n.º 11
0
 def test_barrier(self):
     with threading_helper.wait_threads_exit():
         self.bar = Barrier(NUMTASKS)
         self.running = NUMTASKS
         for i in range(NUMTASKS):
             thread.start_new_thread(self.task2, (i, ))
         verbose_print("waiting for tasks to end")
         self.done_mutex.acquire()
         verbose_print("tasks done")
Ejemplo n.º 12
0
 def test_ident_of_no_threading_threads(self):
     # The ident still must work for the main thread and dummy threads.
     self.assertIsNotNone(threading.currentThread().ident)
     def f():
         ident.append(threading.currentThread().ident)
         done.set()
     done = threading.Event()
     ident = []
     with threading_helper.wait_threads_exit():
         tid = _thread.start_new_thread(f, ())
         done.wait()
         self.assertEqual(ident[0], tid)
     # Kill the "immortal" _DummyThread
     del threading._active[ident[0]]
Ejemplo n.º 13
0
    def test_interrupted_timed_acquire(self):
        # Test to make sure we recompute lock acquisition timeouts when we
        # receive a signal.  Check this by repeatedly interrupting a lock
        # acquire in the main thread, and make sure that the lock acquire times
        # out after the right amount of time.
        # NOTE: this test only behaves as expected if C signals get delivered
        # to the main thread.  Otherwise lock.acquire() itself doesn't get
        # interrupted and the test trivially succeeds.
        self.start = None
        self.end = None
        self.sigs_recvd = 0
        done = thread.allocate_lock()
        done.acquire()
        lock = thread.allocate_lock()
        lock.acquire()

        def my_handler(signum, frame):
            self.sigs_recvd += 1

        old_handler = signal.signal(signal.SIGUSR1, my_handler)
        try:

            def timed_acquire():
                self.start = time.monotonic()
                lock.acquire(timeout=0.5)
                self.end = time.monotonic()

            def send_signals():
                for _ in range(40):
                    time.sleep(0.02)
                    os.kill(process_pid, signal.SIGUSR1)
                done.release()

            with threading_helper.wait_threads_exit():
                # Send the signals from the non-main thread, since the main thread
                # is the only one that can process signals.
                thread.start_new_thread(send_signals, ())
                timed_acquire()
                # Wait for thread to finish
                done.acquire()
                # This allows for some timing and scheduling imprecision
                self.assertLess(self.end - self.start, 2.0)
                self.assertGreater(self.end - self.start, 0.3)
                # If the signal is received several times before PyErr_CheckSignals()
                # is called, the handler will get called less than 40 times. Just
                # check it's been called at least once.
                self.assertGreater(self.sigs_recvd, 0)
        finally:
            signal.signal(signal.SIGUSR1, old_handler)
Ejemplo n.º 14
0
    def test_unraisable_exception(self):
        def task():
            started.release()
            raise ValueError("task failed")

        started = thread.allocate_lock()
        with support.catch_unraisable_exception() as cm:
            with threading_helper.wait_threads_exit():
                started.acquire()
                thread.start_new_thread(task, ())
                started.acquire()

            self.assertEqual(str(cm.unraisable.exc_value), "task failed")
            self.assertIs(cm.unraisable.object, task)
            self.assertEqual(cm.unraisable.err_msg,
                             "Exception ignored in thread started by")
            self.assertIsNotNone(cm.unraisable.exc_traceback)
Ejemplo n.º 15
0
    def test_foreign_thread(self):
        # Check that a "foreign" thread can use the threading module.
        def f(mutex):
            # Calling current_thread() forces an entry for the foreign
            # thread to get made in the threading._active map.
            threading.current_thread()
            mutex.release()

        mutex = threading.Lock()
        mutex.acquire()
        with threading_helper.wait_threads_exit():
            tid = _thread.start_new_thread(f, (mutex,))
            # Wait for the thread to finish.
            mutex.acquire()
        self.assertIn(tid, threading._active)
        self.assertIsInstance(threading._active[tid], threading._DummyThread)
        #Issue 29376
        self.assertTrue(threading._active[tid].is_alive())
        self.assertRegex(repr(threading._active[tid]), '_DummyThread')
        del threading._active[tid]
Ejemplo n.º 16
0
    def test_reacquire(self):
        # Lock needs to be released before re-acquiring.
        lock = self.locktype()
        phase = []

        def f():
            lock.acquire()
            phase.append(None)
            lock.acquire()
            phase.append(None)

        with threading_helper.wait_threads_exit():
            start_new_thread(f, ())
            while len(phase) == 0:
                _wait()
            _wait()
            self.assertEqual(len(phase), 1)
            lock.release()
            while len(phase) == 1:
                _wait()
            self.assertEqual(len(phase), 2)