Skip to content

Commit

Permalink
pythongh-125286: Add test for single-phase init and shared objects.
Browse files Browse the repository at this point in the history
  • Loading branch information
nascheme committed Oct 11, 2024
1 parent b3aa1b5 commit d7ca0ca
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 0 deletions.
32 changes: 32 additions & 0 deletions Lib/test/support/singlephase_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Helper module for _testembed.c test_subinterpreter_finalize test.
"""

import sys

PREFIX = "shared_string_"
SUFFIX = "DByGMRJRSEDp29PkiZQNHA"

def init_sub1():
import _testsinglephase
# Create global object to be shared when imported a second time.
_testsinglephase._shared_list = []
# Create a new interned string, to be shared with the main interpreter.
_testsinglephase._shared_string = sys.intern(PREFIX + SUFFIX)


def init_sub2():
# This sub-interpreter will share a reference to _shared_list with the
# first interpreter, since importing _testsinglephase will not initialize
# the module a second time but will just copy the global dict. This
# situtation used to trigger a bug like gh-125286 if TraceRefs was enabled
# for the build.
import _testsinglephase


def init_main():
global shared_str
# The first sub-interpreter has already interned this string value. The
# return value from intern() will be the same string object created in
# sub-interpreter 1. Assign it to a global so it lives until the main
# interpreter is shutdown.
shared_string = sys.intern(PREFIX + SUFFIX)
41 changes: 41 additions & 0 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -2072,6 +2072,46 @@ static void configure_init_main(PyConfig *config)
}


static int test_subinterpreter_finalize(void)
{
// This test is done by creating two subinterpreters and then sharing
// objects between them by importing a basic single-phase init extension
// (m_size == -1). Then we finalize the interpreters in the reverse order
// so that the interpreter that created the shared objects gets finalized
// first.
_testembed_Py_InitializeFromConfig();

PyThreadState *tstate1 = Py_NewInterpreter();
PyThreadState_Swap(tstate1);
PyRun_SimpleString(
"import test.support.singlephase_helper\n"
"test.support.singlephase_helper.init_sub1\n"
);

PyThreadState *tstate2 = Py_NewInterpreter();
PyThreadState_Swap(tstate2);
PyRun_SimpleString(
"import test.support.singlephase_helper\n"
"test.support.singlephase_helper.init_sub2\n"
);

PyThreadState *main_tstate = _PyRuntime.main_tstate;
PyThreadState_Swap(main_tstate);
PyRun_SimpleString(
"import test.support.singlephase_helper\n"
"test.support.singlephase_helper.init_main\n"
);

PyThreadState_Swap(tstate1);
Py_EndInterpreter(tstate1);
PyThreadState_Swap(tstate2);
Py_EndInterpreter(tstate2);
Py_Finalize();

return 0;
}


static int test_init_run_main(void)
{
PyConfig config;
Expand Down Expand Up @@ -2480,6 +2520,7 @@ static struct TestCase TestCases[] = {
{"test_initconfig_get_api", test_initconfig_get_api},
{"test_initconfig_exit", test_initconfig_exit},
{"test_initconfig_module", test_initconfig_module},
{"test_subinterpreter_finalize", test_subinterpreter_finalize},
{"test_run_main", test_run_main},
{"test_run_main_loop", test_run_main_loop},
{"test_get_argc_argv", test_get_argc_argv},
Expand Down

0 comments on commit d7ca0ca

Please sign in to comment.