mirror of
https://github.com/python/cpython.git
synced 2024-11-26 19:34:19 +08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
2cdfb41d0c
@ -294,7 +294,7 @@ check: _ensure-pre-commit
|
||||
|
||||
.PHONY: serve
|
||||
serve:
|
||||
@echo "The serve target was removed, use htmlview instead (see bpo-36329)"
|
||||
@echo "The serve target was removed, use htmllive instead (see gh-80510)"
|
||||
|
||||
# Targets for daily automated doc build
|
||||
# By default, Sphinx only rebuilds pages where the page content has changed.
|
||||
|
@ -130,6 +130,7 @@ struct _is {
|
||||
uint64_t next_unique_id;
|
||||
/* The linked list of threads, newest first. */
|
||||
PyThreadState *head;
|
||||
_PyThreadStateImpl *preallocated;
|
||||
/* The thread currently executing in the __main__ module, if any. */
|
||||
PyThreadState *main;
|
||||
/* Used in Modules/_threadmodule.c. */
|
||||
@ -278,9 +279,10 @@ struct _is {
|
||||
struct _Py_interp_cached_objects cached_objects;
|
||||
struct _Py_interp_static_objects static_objects;
|
||||
|
||||
Py_ssize_t _interactive_src_count;
|
||||
|
||||
/* the initial PyInterpreterState.threads.head */
|
||||
_PyThreadStateImpl _initial_thread;
|
||||
Py_ssize_t _interactive_src_count;
|
||||
};
|
||||
|
||||
|
||||
|
@ -118,6 +118,9 @@ extern PyTypeObject _PyExc_MemoryError;
|
||||
{ \
|
||||
.id_refcount = -1, \
|
||||
._whence = _PyInterpreterState_WHENCE_NOTSET, \
|
||||
.threads = { \
|
||||
.preallocated = &(INTERP)._initial_thread, \
|
||||
}, \
|
||||
.imports = IMPORTS_INIT, \
|
||||
.ceval = { \
|
||||
.recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
|
||||
|
@ -651,7 +651,19 @@ class timedelta:
|
||||
# guide the C implementation; it's way more convoluted than speed-
|
||||
# ignoring auto-overflow-to-long idiomatic Python could be.
|
||||
|
||||
# XXX Check that all inputs are ints or floats.
|
||||
for name, value in (
|
||||
("days", days),
|
||||
("seconds", seconds),
|
||||
("microseconds", microseconds),
|
||||
("milliseconds", milliseconds),
|
||||
("minutes", minutes),
|
||||
("hours", hours),
|
||||
("weeks", weeks)
|
||||
):
|
||||
if not isinstance(value, (int, float)):
|
||||
raise TypeError(
|
||||
f"unsupported type for timedelta {name} component: {type(value).__name__}"
|
||||
)
|
||||
|
||||
# Final values, all integer.
|
||||
# s and us fit in 32-bit signed ints; d isn't bounded.
|
||||
|
@ -510,6 +510,7 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
|
||||
|
||||
def test_constructor(self):
|
||||
eq = self.assertEqual
|
||||
ra = self.assertRaises
|
||||
td = timedelta
|
||||
|
||||
# Check keyword args to constructor
|
||||
@ -533,6 +534,15 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
|
||||
eq(td(seconds=0.001), td(milliseconds=1))
|
||||
eq(td(milliseconds=0.001), td(microseconds=1))
|
||||
|
||||
# Check type of args to constructor
|
||||
ra(TypeError, lambda: td(weeks='1'))
|
||||
ra(TypeError, lambda: td(days='1'))
|
||||
ra(TypeError, lambda: td(hours='1'))
|
||||
ra(TypeError, lambda: td(minutes='1'))
|
||||
ra(TypeError, lambda: td(seconds='1'))
|
||||
ra(TypeError, lambda: td(milliseconds='1'))
|
||||
ra(TypeError, lambda: td(microseconds='1'))
|
||||
|
||||
def test_computations(self):
|
||||
eq = self.assertEqual
|
||||
td = timedelta
|
||||
|
@ -15,7 +15,6 @@ strict = True
|
||||
|
||||
# Various stricter settings that we can't yet enable
|
||||
# Try to enable these in the following order:
|
||||
disallow_any_generics = False
|
||||
disallow_incomplete_defs = False
|
||||
disallow_untyped_calls = False
|
||||
disallow_untyped_defs = False
|
||||
|
@ -1,5 +1,6 @@
|
||||
import sys
|
||||
import trace
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .runtests import RunTests
|
||||
from .result import State, TestResult, TestStats, Location
|
||||
@ -7,6 +8,9 @@ from .utils import (
|
||||
StrPath, TestName, TestTuple, TestList, FilterDict,
|
||||
printlist, count, format_duration)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
|
||||
# Python uses exit code 1 when an exception is not caught
|
||||
# argparse.ArgumentParser.error() uses exit code 2
|
||||
@ -34,7 +38,7 @@ class TestResults:
|
||||
self.test_times: list[tuple[float, TestName]] = []
|
||||
self.stats = TestStats()
|
||||
# used by --junit-xml
|
||||
self.testsuite_xml: list = []
|
||||
self.testsuite_xml: list['Element'] = []
|
||||
# used by -T with -j
|
||||
self.covered_lines: set[Location] = set()
|
||||
|
||||
|
@ -28,7 +28,7 @@ class JsonFile:
|
||||
file: int | None
|
||||
file_type: str
|
||||
|
||||
def configure_subprocess(self, popen_kwargs: dict) -> None:
|
||||
def configure_subprocess(self, popen_kwargs: dict[str, Any]) -> None:
|
||||
match self.file_type:
|
||||
case JsonFileType.UNIX_FD:
|
||||
# Unix file descriptor
|
||||
|
@ -20,7 +20,7 @@ NEED_TTY = {
|
||||
|
||||
|
||||
def create_worker_process(runtests: WorkerRunTests, output_fd: int,
|
||||
tmp_dir: StrPath | None = None) -> subprocess.Popen:
|
||||
tmp_dir: StrPath | None = None) -> subprocess.Popen[str]:
|
||||
worker_json = runtests.as_json()
|
||||
|
||||
cmd = runtests.create_python_cmd()
|
||||
|
@ -632,8 +632,7 @@ def fd_count():
|
||||
if hasattr(os, 'sysconf'):
|
||||
try:
|
||||
MAXFD = os.sysconf("SC_OPEN_MAX")
|
||||
except (OSError, ValueError):
|
||||
# gh-118201: ValueError is raised intermittently on iOS
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
old_modes = None
|
||||
|
@ -4439,6 +4439,14 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL)
|
||||
self.assertRaises(BufferError, memoryview, x)
|
||||
|
||||
def test_bytearray_release_buffer_read_flag(self):
|
||||
# See https://github.com/python/cpython/issues/126980
|
||||
obj = bytearray(b'abc')
|
||||
with self.assertRaises(SystemError):
|
||||
obj.__buffer__(inspect.BufferFlags.READ)
|
||||
with self.assertRaises(SystemError):
|
||||
obj.__buffer__(inspect.BufferFlags.WRITE)
|
||||
|
||||
@support.cpython_only
|
||||
def test_pybuffer_size_from_format(self):
|
||||
# basic tests
|
||||
|
@ -23,6 +23,7 @@ class StressTests(TestBase):
|
||||
alive.append(interp)
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
@threading_helper.requires_working_threading()
|
||||
def test_create_many_threaded(self):
|
||||
alive = []
|
||||
def task():
|
||||
@ -32,6 +33,35 @@ class StressTests(TestBase):
|
||||
with threading_helper.start_threads(threads):
|
||||
pass
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
@threading_helper.requires_working_threading()
|
||||
def test_many_threads_running_interp_in_other_interp(self):
|
||||
interp = interpreters.create()
|
||||
|
||||
script = f"""if True:
|
||||
import _interpreters
|
||||
_interpreters.run_string({interp.id}, '1')
|
||||
"""
|
||||
|
||||
def run():
|
||||
interp = interpreters.create()
|
||||
alreadyrunning = (f'{interpreters.InterpreterError}: '
|
||||
'interpreter already running')
|
||||
success = False
|
||||
while not success:
|
||||
try:
|
||||
interp.exec(script)
|
||||
except interpreters.ExecutionFailed as exc:
|
||||
if exc.excinfo.msg != 'interpreter already running':
|
||||
raise # re-raise
|
||||
assert exc.excinfo.type.__name__ == 'InterpreterError'
|
||||
else:
|
||||
success = True
|
||||
|
||||
threads = (threading.Thread(target=run) for _ in range(200))
|
||||
with threading_helper.start_threads(threads):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Test needs to be a package, so we can do relative imports.
|
||||
|
@ -2447,8 +2447,8 @@ class TestInvalidFD(unittest.TestCase):
|
||||
support.is_emscripten or support.is_wasi,
|
||||
"musl libc issue on Emscripten/WASI, bpo-46390"
|
||||
)
|
||||
@unittest.skipIf(support.is_apple_mobile, "gh-118201: Test is flaky on iOS")
|
||||
def test_fpathconf(self):
|
||||
self.assertIn("PC_NAME_MAX", os.pathconf_names)
|
||||
self.check(os.pathconf, "PC_NAME_MAX")
|
||||
self.check(os.fpathconf, "PC_NAME_MAX")
|
||||
self.check_bool(os.pathconf, "PC_NAME_MAX")
|
||||
|
@ -568,10 +568,38 @@ class PosixTester(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(hasattr(posix, 'confstr'),
|
||||
'test needs posix.confstr()')
|
||||
@unittest.skipIf(support.is_apple_mobile, "gh-118201: Test is flaky on iOS")
|
||||
def test_confstr(self):
|
||||
self.assertRaises(ValueError, posix.confstr, "CS_garbage")
|
||||
self.assertEqual(len(posix.confstr("CS_PATH")) > 0, True)
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "unrecognized configuration name"
|
||||
):
|
||||
posix.confstr("CS_garbage")
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
TypeError, "configuration names must be strings or integers"
|
||||
):
|
||||
posix.confstr(1.23)
|
||||
|
||||
path = posix.confstr("CS_PATH")
|
||||
self.assertGreater(len(path), 0)
|
||||
self.assertEqual(posix.confstr(posix.confstr_names["CS_PATH"]), path)
|
||||
|
||||
@unittest.skipUnless(hasattr(posix, 'sysconf'),
|
||||
'test needs posix.sysconf()')
|
||||
def test_sysconf(self):
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "unrecognized configuration name"
|
||||
):
|
||||
posix.sysconf("SC_garbage")
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
TypeError, "configuration names must be strings or integers"
|
||||
):
|
||||
posix.sysconf(1.23)
|
||||
|
||||
arg_max = posix.sysconf("SC_ARG_MAX")
|
||||
self.assertGreater(arg_max, 0)
|
||||
self.assertEqual(
|
||||
posix.sysconf(posix.sysconf_names["SC_ARG_MAX"]), arg_max)
|
||||
|
||||
@unittest.skipUnless(hasattr(posix, 'dup2'),
|
||||
'test needs posix.dup2()')
|
||||
|
@ -0,0 +1,3 @@
|
||||
Fix :meth:`~object.__buffer__` of :class:`bytearray` crashing when
|
||||
:attr:`~inspect.BufferFlags.READ` or :attr:`~inspect.BufferFlags.WRITE` are
|
||||
passed as flags.
|
@ -0,0 +1,2 @@
|
||||
Fixed intermittent failures of :any:`os.confstr`, :any:`os.pathconf` and
|
||||
:any:`os.sysconf` on iOS and Android.
|
@ -0,0 +1,2 @@
|
||||
Raise :exc:`TypeError` in :meth:`!_pydatetime.timedelta.__new__` if the passed arguments are not :class:`int` or :class:`float`, so that the Python
|
||||
implementation is in line with the C implementation.
|
@ -0,0 +1 @@
|
||||
Makes the presence of the :mod:`turtle` module dependent on the Tcl/Tk installer option. Previously, the module was always installed but would be unusable without Tcl/Tk.
|
@ -6730,6 +6730,7 @@ load_build(PickleState *st, UnpicklerObject *self)
|
||||
}
|
||||
if (PyObject_SetItem(dict, d_key, d_value) < 0) {
|
||||
Py_DECREF(d_key);
|
||||
Py_DECREF(dict);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(d_key);
|
||||
|
10
Modules/clinic/posixmodule.c.h
generated
10
Modules/clinic/posixmodule.c.h
generated
@ -10128,7 +10128,7 @@ os_fpathconf(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||
if (fd < 0) {
|
||||
goto exit;
|
||||
}
|
||||
if (!conv_path_confname(args[1], &name)) {
|
||||
if (!conv_confname(module, args[1], &name, "pathconf_names")) {
|
||||
goto exit;
|
||||
}
|
||||
_return_value = os_fpathconf_impl(module, fd, name);
|
||||
@ -10203,7 +10203,7 @@ os_pathconf(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
|
||||
if (!path_converter(args[0], &path)) {
|
||||
goto exit;
|
||||
}
|
||||
if (!conv_path_confname(args[1], &name)) {
|
||||
if (!conv_confname(module, args[1], &name, "pathconf_names")) {
|
||||
goto exit;
|
||||
}
|
||||
_return_value = os_pathconf_impl(module, &path, name);
|
||||
@ -10241,7 +10241,7 @@ os_confstr(PyObject *module, PyObject *arg)
|
||||
PyObject *return_value = NULL;
|
||||
int name;
|
||||
|
||||
if (!conv_confstr_confname(arg, &name)) {
|
||||
if (!conv_confname(module, arg, &name, "confstr_names")) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = os_confstr_impl(module, name);
|
||||
@ -10273,7 +10273,7 @@ os_sysconf(PyObject *module, PyObject *arg)
|
||||
int name;
|
||||
long _return_value;
|
||||
|
||||
if (!conv_sysconf_confname(arg, &name)) {
|
||||
if (!conv_confname(module, arg, &name, "sysconf_names")) {
|
||||
goto exit;
|
||||
}
|
||||
_return_value = os_sysconf_impl(module, name);
|
||||
@ -13114,4 +13114,4 @@ os__create_environ(PyObject *module, PyObject *Py_UNUSED(ignored))
|
||||
#ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
|
||||
#define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
|
||||
#endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */
|
||||
/*[clinic end generated code: output=5358a13b4ce6148b input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=7ee14f5e880092f5 input=a9049054013a1b77]*/
|
||||
|
@ -3113,18 +3113,22 @@ class Py_off_t_return_converter(long_return_converter):
|
||||
type = 'Py_off_t'
|
||||
conversion_fn = 'PyLong_FromPy_off_t'
|
||||
|
||||
class path_confname_converter(CConverter):
|
||||
class confname_converter(CConverter):
|
||||
type="int"
|
||||
converter="conv_path_confname"
|
||||
converter="conv_confname"
|
||||
|
||||
class confstr_confname_converter(path_confname_converter):
|
||||
converter='conv_confstr_confname'
|
||||
def converter_init(self, *, table):
|
||||
self.table = table
|
||||
|
||||
class sysconf_confname_converter(path_confname_converter):
|
||||
converter="conv_sysconf_confname"
|
||||
def parse_arg(self, argname, displayname, *, limited_capi):
|
||||
return self.format_code("""
|
||||
if (!{converter}(module, {argname}, &{paramname}, "{table}")) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""", argname=argname, converter=self.converter, table=self.table)
|
||||
|
||||
[python start generated code]*/
|
||||
/*[python end generated code: output=da39a3ee5e6b4b0d input=1860d32584c2a539]*/
|
||||
/*[python end generated code: output=da39a3ee5e6b4b0d input=8189d5ae78244626]*/
|
||||
|
||||
/*[clinic input]
|
||||
|
||||
@ -13547,46 +13551,38 @@ struct constdef {
|
||||
};
|
||||
|
||||
static int
|
||||
conv_confname(PyObject *arg, int *valuep, struct constdef *table,
|
||||
size_t tablesize)
|
||||
conv_confname(PyObject *module, PyObject *arg, int *valuep, const char *tablename)
|
||||
{
|
||||
if (PyLong_Check(arg)) {
|
||||
if (PyUnicode_Check(arg)) {
|
||||
PyObject *table = PyObject_GetAttrString(module, tablename);
|
||||
if (table == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
arg = PyObject_GetItem(table, arg);
|
||||
Py_DECREF(table);
|
||||
if (arg == NULL) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "unrecognized configuration name");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
Py_INCREF(arg); // Match the Py_DECREF below.
|
||||
}
|
||||
|
||||
int success = 0;
|
||||
if (!PyLong_Check(arg)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"configuration names must be strings or integers");
|
||||
} else {
|
||||
int value = PyLong_AsInt(arg);
|
||||
if (value == -1 && PyErr_Occurred())
|
||||
return 0;
|
||||
*valuep = value;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* look up the value in the table using a binary search */
|
||||
size_t lo = 0;
|
||||
size_t mid;
|
||||
size_t hi = tablesize;
|
||||
int cmp;
|
||||
const char *confname;
|
||||
if (!PyUnicode_Check(arg)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"configuration names must be strings or integers");
|
||||
return 0;
|
||||
if (!(value == -1 && PyErr_Occurred())) {
|
||||
*valuep = value;
|
||||
success = 1;
|
||||
}
|
||||
confname = PyUnicode_AsUTF8(arg);
|
||||
if (confname == NULL)
|
||||
return 0;
|
||||
while (lo < hi) {
|
||||
mid = (lo + hi) / 2;
|
||||
cmp = strcmp(confname, table[mid].name);
|
||||
if (cmp < 0)
|
||||
hi = mid;
|
||||
else if (cmp > 0)
|
||||
lo = mid + 1;
|
||||
else {
|
||||
*valuep = table[mid].value;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "unrecognized configuration name");
|
||||
return 0;
|
||||
}
|
||||
Py_DECREF(arg);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@ -13677,14 +13673,6 @@ static struct constdef posix_constants_pathconf[] = {
|
||||
{"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
conv_path_confname(PyObject *arg, int *valuep)
|
||||
{
|
||||
return conv_confname(arg, valuep, posix_constants_pathconf,
|
||||
sizeof(posix_constants_pathconf)
|
||||
/ sizeof(struct constdef));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -13693,7 +13681,7 @@ conv_path_confname(PyObject *arg, int *valuep)
|
||||
os.fpathconf -> long
|
||||
|
||||
fd: fildes
|
||||
name: path_confname
|
||||
name: confname(table="pathconf_names")
|
||||
/
|
||||
|
||||
Return the configuration limit name for the file descriptor fd.
|
||||
@ -13703,7 +13691,7 @@ If there is no limit, return -1.
|
||||
|
||||
static long
|
||||
os_fpathconf_impl(PyObject *module, int fd, int name)
|
||||
/*[clinic end generated code: output=d5b7042425fc3e21 input=5b8d2471cfaae186]*/
|
||||
/*[clinic end generated code: output=d5b7042425fc3e21 input=023d44589c9ed6aa]*/
|
||||
{
|
||||
long limit;
|
||||
|
||||
@ -13721,7 +13709,7 @@ os_fpathconf_impl(PyObject *module, int fd, int name)
|
||||
/*[clinic input]
|
||||
os.pathconf -> long
|
||||
path: path_t(allow_fd='PATH_HAVE_FPATHCONF')
|
||||
name: path_confname
|
||||
name: confname(table="pathconf_names")
|
||||
|
||||
Return the configuration limit name for the file or directory path.
|
||||
|
||||
@ -13732,7 +13720,7 @@ On some platforms, path may also be specified as an open file descriptor.
|
||||
|
||||
static long
|
||||
os_pathconf_impl(PyObject *module, path_t *path, int name)
|
||||
/*[clinic end generated code: output=5bedee35b293a089 input=bc3e2a985af27e5e]*/
|
||||
/*[clinic end generated code: output=5bedee35b293a089 input=6f6072f57b10c787]*/
|
||||
{
|
||||
long limit;
|
||||
|
||||
@ -13909,19 +13897,11 @@ static struct constdef posix_constants_confstr[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
conv_confstr_confname(PyObject *arg, int *valuep)
|
||||
{
|
||||
return conv_confname(arg, valuep, posix_constants_confstr,
|
||||
sizeof(posix_constants_confstr)
|
||||
/ sizeof(struct constdef));
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os.confstr
|
||||
|
||||
name: confstr_confname
|
||||
name: confname(table="confstr_names")
|
||||
/
|
||||
|
||||
Return a string-valued system configuration variable.
|
||||
@ -13929,7 +13909,7 @@ Return a string-valued system configuration variable.
|
||||
|
||||
static PyObject *
|
||||
os_confstr_impl(PyObject *module, int name)
|
||||
/*[clinic end generated code: output=bfb0b1b1e49b9383 input=18fb4d0567242e65]*/
|
||||
/*[clinic end generated code: output=bfb0b1b1e49b9383 input=4c6ffca2837ec959]*/
|
||||
{
|
||||
PyObject *result = NULL;
|
||||
char buffer[255];
|
||||
@ -14466,18 +14446,10 @@ static struct constdef posix_constants_sysconf[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
conv_sysconf_confname(PyObject *arg, int *valuep)
|
||||
{
|
||||
return conv_confname(arg, valuep, posix_constants_sysconf,
|
||||
sizeof(posix_constants_sysconf)
|
||||
/ sizeof(struct constdef));
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os.sysconf -> long
|
||||
name: sysconf_confname
|
||||
name: confname(table="sysconf_names")
|
||||
/
|
||||
|
||||
Return an integer-valued system configuration variable.
|
||||
@ -14485,7 +14457,7 @@ Return an integer-valued system configuration variable.
|
||||
|
||||
static long
|
||||
os_sysconf_impl(PyObject *module, int name)
|
||||
/*[clinic end generated code: output=3662f945fc0cc756 input=279e3430a33f29e4]*/
|
||||
/*[clinic end generated code: output=3662f945fc0cc756 input=930b8f23b5d15086]*/
|
||||
{
|
||||
long value;
|
||||
|
||||
@ -14498,40 +14470,15 @@ os_sysconf_impl(PyObject *module, int name)
|
||||
#endif /* HAVE_SYSCONF */
|
||||
|
||||
|
||||
/* This code is used to ensure that the tables of configuration value names
|
||||
* are in sorted order as required by conv_confname(), and also to build
|
||||
* the exported dictionaries that are used to publish information about the
|
||||
* names available on the host platform.
|
||||
*
|
||||
* Sorting the table at runtime ensures that the table is properly ordered
|
||||
* when used, even for platforms we're not able to test on. It also makes
|
||||
* it easier to add additional entries to the tables.
|
||||
*/
|
||||
|
||||
static int
|
||||
cmp_constdefs(const void *v1, const void *v2)
|
||||
{
|
||||
const struct constdef *c1 =
|
||||
(const struct constdef *) v1;
|
||||
const struct constdef *c2 =
|
||||
(const struct constdef *) v2;
|
||||
|
||||
return strcmp(c1->name, c2->name);
|
||||
}
|
||||
|
||||
static int
|
||||
setup_confname_table(struct constdef *table, size_t tablesize,
|
||||
const char *tablename, PyObject *module)
|
||||
{
|
||||
PyObject *d = NULL;
|
||||
size_t i;
|
||||
|
||||
qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs);
|
||||
d = PyDict_New();
|
||||
PyObject *d = PyDict_New();
|
||||
if (d == NULL)
|
||||
return -1;
|
||||
|
||||
for (i=0; i < tablesize; ++i) {
|
||||
for (size_t i=0; i < tablesize; ++i) {
|
||||
PyObject *o = PyLong_FromLong(table[i].value);
|
||||
if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) {
|
||||
Py_XDECREF(o);
|
||||
|
@ -52,8 +52,9 @@ bytearray_getbuffer(PyObject *self, Py_buffer *view, int flags)
|
||||
}
|
||||
|
||||
void *ptr = (void *) PyByteArray_AS_STRING(obj);
|
||||
/* cannot fail if view != NULL and readonly == 0 */
|
||||
(void)PyBuffer_FillInfo(view, (PyObject*)obj, ptr, Py_SIZE(obj), 0, flags);
|
||||
if (PyBuffer_FillInfo(view, (PyObject*)obj, ptr, Py_SIZE(obj), 0, flags) < 0) {
|
||||
return -1;
|
||||
}
|
||||
obj->ob_exports++;
|
||||
return 0;
|
||||
}
|
||||
|
@ -629,6 +629,8 @@ init_interpreter(PyInterpreterState *interp,
|
||||
assert(next != NULL || (interp == runtime->interpreters.main));
|
||||
interp->next = next;
|
||||
|
||||
interp->threads.preallocated = &interp->_initial_thread;
|
||||
|
||||
// We would call _PyObject_InitState() at this point
|
||||
// if interp->feature_flags were alredy set.
|
||||
|
||||
@ -766,7 +768,6 @@ PyInterpreterState_New(void)
|
||||
return interp;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
||||
{
|
||||
@ -910,6 +911,9 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
||||
// XXX Once we have one allocator per interpreter (i.e.
|
||||
// per-interpreter GC) we must ensure that all of the interpreter's
|
||||
// objects have been cleaned up at the point.
|
||||
|
||||
// We could clear interp->threads.freelist here
|
||||
// if it held more than just the initial thread state.
|
||||
}
|
||||
|
||||
|
||||
@ -1386,22 +1390,45 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous)
|
||||
return res;
|
||||
}
|
||||
|
||||
static _PyThreadStateImpl *
|
||||
alloc_threadstate(void)
|
||||
static void
|
||||
reset_threadstate(_PyThreadStateImpl *tstate)
|
||||
{
|
||||
return PyMem_RawCalloc(1, sizeof(_PyThreadStateImpl));
|
||||
// Set to _PyThreadState_INIT directly?
|
||||
memcpy(tstate,
|
||||
&initial._main_interpreter._initial_thread,
|
||||
sizeof(*tstate));
|
||||
}
|
||||
|
||||
static _PyThreadStateImpl *
|
||||
alloc_threadstate(PyInterpreterState *interp)
|
||||
{
|
||||
_PyThreadStateImpl *tstate;
|
||||
|
||||
// Try the preallocated tstate first.
|
||||
tstate = _Py_atomic_exchange_ptr(&interp->threads.preallocated, NULL);
|
||||
|
||||
// Fall back to the allocator.
|
||||
if (tstate == NULL) {
|
||||
tstate = PyMem_RawCalloc(1, sizeof(_PyThreadStateImpl));
|
||||
if (tstate == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
reset_threadstate(tstate);
|
||||
}
|
||||
return tstate;
|
||||
}
|
||||
|
||||
static void
|
||||
free_threadstate(_PyThreadStateImpl *tstate)
|
||||
{
|
||||
PyInterpreterState *interp = tstate->base.interp;
|
||||
// The initial thread state of the interpreter is allocated
|
||||
// as part of the interpreter state so should not be freed.
|
||||
if (tstate == &tstate->base.interp->_initial_thread) {
|
||||
// Restore to _PyThreadState_INIT.
|
||||
memcpy(tstate,
|
||||
&initial._main_interpreter._initial_thread,
|
||||
sizeof(*tstate));
|
||||
if (tstate == &interp->_initial_thread) {
|
||||
// Make it available again.
|
||||
reset_threadstate(tstate);
|
||||
assert(interp->threads.preallocated == NULL);
|
||||
_Py_atomic_store_ptr(&interp->threads.preallocated, tstate);
|
||||
}
|
||||
else {
|
||||
PyMem_RawFree(tstate);
|
||||
@ -1492,66 +1519,38 @@ add_threadstate(PyInterpreterState *interp, PyThreadState *tstate,
|
||||
static PyThreadState *
|
||||
new_threadstate(PyInterpreterState *interp, int whence)
|
||||
{
|
||||
_PyThreadStateImpl *tstate;
|
||||
_PyRuntimeState *runtime = interp->runtime;
|
||||
// We don't need to allocate a thread state for the main interpreter
|
||||
// (the common case), but doing it later for the other case revealed a
|
||||
// reentrancy problem (deadlock). So for now we always allocate before
|
||||
// taking the interpreters lock. See GH-96071.
|
||||
_PyThreadStateImpl *new_tstate = alloc_threadstate();
|
||||
int used_newtstate;
|
||||
if (new_tstate == NULL) {
|
||||
// Allocate the thread state.
|
||||
_PyThreadStateImpl *tstate = alloc_threadstate(interp);
|
||||
if (tstate == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
Py_ssize_t qsbr_idx = _Py_qsbr_reserve(interp);
|
||||
if (qsbr_idx < 0) {
|
||||
PyMem_RawFree(new_tstate);
|
||||
free_threadstate(tstate);
|
||||
return NULL;
|
||||
}
|
||||
int32_t tlbc_idx = _Py_ReserveTLBCIndex(interp);
|
||||
if (tlbc_idx < 0) {
|
||||
PyMem_RawFree(new_tstate);
|
||||
free_threadstate(tstate);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We serialize concurrent creation to protect global state. */
|
||||
HEAD_LOCK(runtime);
|
||||
HEAD_LOCK(interp->runtime);
|
||||
|
||||
// Initialize the new thread state.
|
||||
interp->threads.next_unique_id += 1;
|
||||
uint64_t id = interp->threads.next_unique_id;
|
||||
|
||||
// Allocate the thread state and add it to the interpreter.
|
||||
PyThreadState *old_head = interp->threads.head;
|
||||
if (old_head == NULL) {
|
||||
// It's the interpreter's initial thread state.
|
||||
used_newtstate = 0;
|
||||
tstate = &interp->_initial_thread;
|
||||
}
|
||||
// XXX Re-use interp->_initial_thread if not in use?
|
||||
else {
|
||||
// Every valid interpreter must have at least one thread.
|
||||
assert(id > 1);
|
||||
assert(old_head->prev == NULL);
|
||||
used_newtstate = 1;
|
||||
tstate = new_tstate;
|
||||
// Set to _PyThreadState_INIT.
|
||||
memcpy(tstate,
|
||||
&initial._main_interpreter._initial_thread,
|
||||
sizeof(*tstate));
|
||||
}
|
||||
|
||||
init_threadstate(tstate, interp, id, whence);
|
||||
|
||||
// Add the new thread state to the interpreter.
|
||||
PyThreadState *old_head = interp->threads.head;
|
||||
add_threadstate(interp, (PyThreadState *)tstate, old_head);
|
||||
|
||||
HEAD_UNLOCK(runtime);
|
||||
if (!used_newtstate) {
|
||||
// Must be called with lock unlocked to avoid re-entrancy deadlock.
|
||||
PyMem_RawFree(new_tstate);
|
||||
}
|
||||
else {
|
||||
}
|
||||
HEAD_UNLOCK(interp->runtime);
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
// Must be called with lock unlocked to avoid lock ordering deadlocks.
|
||||
|
@ -70,8 +70,8 @@ Select Customize to review current options.</String>
|
||||
<String Id="Include_docHelpLabel">Installs the Python documentation files.</String>
|
||||
<String Id="Include_pipLabel">&pip</String>
|
||||
<String Id="Include_pipHelpLabel">Installs pip, which can download and install other Python packages.</String>
|
||||
<String Id="Include_tcltkLabel">tcl/tk and &IDLE</String>
|
||||
<String Id="Include_tcltkHelpLabel">Installs tkinter and the IDLE development environment.</String>
|
||||
<String Id="Include_tcltkLabel">Tcl/Tk, turtle and &IDLE</String>
|
||||
<String Id="Include_tcltkHelpLabel">Installs tkinter, turtle and the IDLE development environment.</String>
|
||||
<String Id="Include_testLabel">Python &test suite</String>
|
||||
<String Id="Include_testHelpLabel">Installs the standard library test suite.</String>
|
||||
<String Id="Include_launcherLabel">py &launcher</String>
|
||||
|
@ -19,6 +19,7 @@
|
||||
<InstallFiles Include="$(PySourcePath)Lib\**\*"
|
||||
Exclude="$(PySourcePath)Lib\**\*.pyc;
|
||||
$(PySourcePath)Lib\**\*.pyo;
|
||||
$(PySourcePath)Lib\turtle.py;
|
||||
$(PySourcePath)Lib\site-packages\README;
|
||||
@(ExcludeFolders->'$(PySourcePath)%(Identity)\*');
|
||||
@(ExcludeFolders->'$(PySourcePath)%(Identity)\**\*')">
|
||||
@ -32,4 +33,4 @@
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -28,7 +28,7 @@
|
||||
<Group>tcltk_lib</Group>
|
||||
</InstallFiles>
|
||||
|
||||
<InstallFiles Include="$(PySourcePath)Lib\tkinter\**\*;$(PySourcePath)Lib\idlelib\**\*;$(PySourcePath)Lib\turtledemo\**\*"
|
||||
<InstallFiles Include="$(PySourcePath)Lib\tkinter\**\*;$(PySourcePath)Lib\idlelib\**\*;$(PySourcePath)Lib\turtledemo\**\*;$(PySourcePath)Lib\turtle.py"
|
||||
Exclude="$(PySourcePath)Lib\**\*.pyc;$(PySourcePath)Lib\**\*.pyo">
|
||||
<SourceBase>$(PySourcePath)</SourceBase>
|
||||
<Source>!(bindpath.src)</Source>
|
||||
@ -39,4 +39,4 @@
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user