Skip to content

Commit 30a3947

Browse files
authored
Merge branch 'main' into fix-json-tool
2 parents ed78614 + b485e50 commit 30a3947

File tree

10 files changed

+47
-27
lines changed

10 files changed

+47
-27
lines changed

Include/cpython/pystate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ struct _ts {
157157
*/
158158
unsigned long native_thread_id;
159159

160+
/* List of objects that still need to be cleaned up, singly linked
161+
* via their gc headers' gc_next pointers. The list is populated by
162+
* _PyTrash_thread_deposit_object and cleaned up by
163+
* _PyTrash_thread_destroy_chain.
164+
*/
160165
PyObject *delete_later;
161166

162167
/* Tagged pointer to top-most critical section, or zero if there is no

Include/internal/pycore_interp_structs.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,6 @@ enum _GCPhase {
203203
#define NUM_GENERATIONS 3
204204

205205
struct _gc_runtime_state {
206-
/* List of objects that still need to be cleaned up, singly linked
207-
* via their gc headers' gc_prev pointers. */
208-
PyObject *trash_delete_later;
209-
/* Current call-stack depth of tp_dealloc calls. */
210-
int trash_delete_nesting;
211-
212206
/* Is automatic collection enabled? */
213207
int enabled;
214208
int debug;

Lib/multiprocessing/dummy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
class DummyProcess(threading.Thread):
3535

36-
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
36+
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None):
3737
threading.Thread.__init__(self, group, target, name, args, kwargs)
3838
self._pid = None
3939
self._children = weakref.WeakKeyDictionary()

Lib/multiprocessing/process.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class BaseProcess(object):
7777
def _Popen(self):
7878
raise NotImplementedError
7979

80-
def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
80+
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None,
8181
*, daemon=None):
8282
assert group is None, 'group argument must be None for now'
8383
count = next(_process_counter)
@@ -89,7 +89,7 @@ def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
8989
self._closed = False
9090
self._target = target
9191
self._args = tuple(args)
92-
self._kwargs = dict(kwargs)
92+
self._kwargs = dict(kwargs) if kwargs else {}
9393
self._name = name or type(self).__name__ + '-' + \
9494
':'.join(str(i) for i in self._identity)
9595
if daemon is not None:

Lib/test/_test_multiprocessing.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5278,6 +5278,23 @@ def test_invalid_handles(self):
52785278
multiprocessing.connection.Connection, -1)
52795279

52805280

5281+
#
5282+
# Regression tests for BaseProcess kwargs handling
5283+
#
5284+
5285+
class TestBaseProcessKwargs(unittest.TestCase):
5286+
def test_default_kwargs_not_shared_between_instances(self):
5287+
# Creating multiple Process instances without passing kwargs
5288+
# must create independent empty dicts (no shared state).
5289+
p1 = multiprocessing.Process(target=lambda: None)
5290+
p2 = multiprocessing.Process(target=lambda: None)
5291+
self.assertIsInstance(p1._kwargs, dict)
5292+
self.assertIsInstance(p2._kwargs, dict)
5293+
self.assertIsNot(p1._kwargs, p2._kwargs)
5294+
# Mutating one should not affect the other
5295+
p1._kwargs['x'] = 1
5296+
self.assertNotIn('x', p2._kwargs)
5297+
52815298

52825299
@hashlib_helper.requires_hashdigest('sha256')
52835300
class OtherTest(unittest.TestCase):

Lib/test/test_math.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,9 @@ def __rmul__(self, other):
14851485

14861486
# Error cases that arose during development
14871487
args = ((-5, -5, 10), (1.5, 4611686018427387904, 2305843009213693952))
1488-
self.assertEqual(sumprod(*args), 0.0)
1488+
self.assertEqual(sumprod(*args), -7.5)
1489+
self.assertEqual(sumprod([-0.01, 1, -1, 0.01], [1, 1, 1, 1]), 0.0)
1490+
self.assertEqual(sumprod([1, 1, 1, 1], [-0.01, 1, -1, 0.01], ), 0.0)
14891491

14901492
@requires_IEEE_754
14911493
@unittest.skipIf(HAVE_DOUBLE_ROUNDING,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed a missing case in :func:`math.sumprod` where a low precision path was
2+
taken when an int/int input pair followed a float input.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:class:`!multiprocessing.BaseProcess` defaults ``kwargs`` to ``None`` instead of a shared dictionary.

Modules/mathmodule.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2937,32 +2937,31 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
29372937

29382938
if (!finished) {
29392939
double flt_p, flt_q;
2940-
bool p_type_float = PyFloat_CheckExact(p_i);
2941-
bool q_type_float = PyFloat_CheckExact(q_i);
2942-
if (p_type_float && q_type_float) {
2943-
flt_p = PyFloat_AS_DOUBLE(p_i);
2944-
flt_q = PyFloat_AS_DOUBLE(q_i);
2945-
} else if (p_type_float && (PyLong_CheckExact(q_i) || PyBool_Check(q_i))) {
2946-
/* We care about float/int pairs and int/float pairs because
2947-
they arise naturally in several use cases such as price
2948-
times quantity, measurements with integer weights, or
2949-
data selected by a vector of bools. */
2940+
2941+
if (PyFloat_CheckExact(p_i)) {
29502942
flt_p = PyFloat_AS_DOUBLE(p_i);
2951-
flt_q = PyLong_AsDouble(q_i);
2952-
if (flt_q == -1.0 && PyErr_Occurred()) {
2943+
} else if (PyLong_CheckExact(p_i) || PyBool_Check(p_i)) {
2944+
flt_p = PyLong_AsDouble(p_i);
2945+
if (flt_p == -1.0 && PyErr_Occurred()) {
29532946
PyErr_Clear();
29542947
goto finalize_flt_path;
29552948
}
2956-
} else if (q_type_float && (PyLong_CheckExact(p_i) || PyBool_Check(p_i))) {
2949+
} else {
2950+
goto finalize_flt_path;
2951+
}
2952+
2953+
if (PyFloat_CheckExact(q_i)) {
29572954
flt_q = PyFloat_AS_DOUBLE(q_i);
2958-
flt_p = PyLong_AsDouble(p_i);
2959-
if (flt_p == -1.0 && PyErr_Occurred()) {
2955+
} else if (PyLong_CheckExact(q_i) || PyBool_Check(q_i)) {
2956+
flt_q = PyLong_AsDouble(q_i);
2957+
if (flt_q == -1.0 && PyErr_Occurred()) {
29602958
PyErr_Clear();
29612959
goto finalize_flt_path;
29622960
}
29632961
} else {
29642962
goto finalize_flt_path;
29652963
}
2964+
29662965
TripleLength new_flt_total = tl_fma(flt_p, flt_q, flt_total);
29672966
if (isfinite(new_flt_total.hi)) {
29682967
flt_total = new_flt_total;

Objects/object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3051,7 +3051,7 @@ Py_ReprLeave(PyObject *obj)
30513051

30523052
/* Trashcan support. */
30533053

3054-
/* Add op to the gcstate->trash_delete_later list. Called when the current
3054+
/* Add op to the tstate->delete_later list. Called when the current
30553055
* call-stack depth gets large. op must be a gc'ed object, with refcount 0.
30563056
* Py_DECREF must already have been called on it.
30573057
*/
@@ -3077,7 +3077,7 @@ _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op)
30773077
tstate->delete_later = op;
30783078
}
30793079

3080-
/* Deallocate all the objects in the gcstate->trash_delete_later list.
3080+
/* Deallocate all the objects in the tstate->delete_later list.
30813081
* Called when the call-stack unwinds again. */
30823082
void
30833083
_PyTrash_thread_destroy_chain(PyThreadState *tstate)

0 commit comments

Comments
 (0)