diff -r 418ab34fd1ce Lib/test/test_thread.py --- a/Lib/test/test_thread.py Sat May 30 00:53:26 2015 +0300 +++ b/Lib/test/test_thread.py Fri May 29 16:01:42 2015 -0700 @@ -241,6 +241,62 @@ self.assertEqual(os.read(self.read_fd, 2), "OK", "Unable to fork() in thread") + @unittest.skipIf(sys.platform.startswith('win'), + "This test is only appropriate for POSIX-like systems.") + @test_support.reap_threads + def test_replacement_threads_in_child(self): + """Test that sys._current_frames is aware of threads started in the child.""" + + stop = False + + started_t1 = [] + started_t2 = [] + + def do_nothing(): + started_t1 + started_t1.append(True) + while not stop: + pass + + def do_nothing2(): + started_t2.append(True) + while not stop: + pass + + # Before the fork, we start do_nothing. In the child, we start do_nothing2. + # it should be the case that, in the child, the frame for do_nothing2 shows + # up in sys._current_frames() + try: + t1 = thread.start_new_thread(do_nothing, ()) + while not started_t1: + time.sleep(.1) + r_fd, w_fd = os.pipe() + pid = os.fork() + if pid == 0: # child + try: + os.close(r_fd) + t2 = thread.start_new_thread(do_nothing2, ()) + while not started_t2: + time.sleep(.1) + running_names = [ + frame.f_code.co_name for frame in sys._current_frames().values()] + with os.fdopen(w_fd, 'w') as f: + f.write(' '.join(name for name in running_names + if name != 'test_replacement_threads_in_child')) + except: + traceback.print_exc() + os._exit(1) + finally: + os._exit(0) + else: # parent + os.close(w_fd) + with os.fdopen(r_fd) as f: + running_thread = f.read() + self.assertEqual(0, os.waitpid(pid, 0)[1]) + self.assertEqual(running_thread, 'do_nothing2') + finally: + stop = True + def tearDown(self): try: os.close(self.read_fd) diff -r 418ab34fd1ce Python/pystate.c --- a/Python/pystate.c Sat May 30 00:53:26 2015 +0300 +++ b/Python/pystate.c Fri May 29 16:01:42 2015 -0700 @@ -480,7 +480,9 @@ id = PyInt_FromLong(t->thread_id); if (id == NULL) goto Fail; - stat = PyDict_SetItem(result, id, (PyObject *)frame); + stat = PyDict_Contains(result, id); + if (stat == 0) + stat = PyDict_SetItem(result, id, (PyObject *)frame); Py_DECREF(id); if (stat < 0) goto Fail;