@@ -113,17 +113,18 @@ As a consequence of this, split keys have a maximum size of 16.
113
113
#define PyDict_MINSIZE 8
114
114
115
115
#include "Python.h"
116
- #include "pycore_bitutils.h" // _Py_bit_length
117
- #include "pycore_call.h" // _PyObject_CallNoArgs()
118
- #include "pycore_ceval.h" // _PyEval_GetBuiltin()
119
- #include "pycore_code.h" // stats
120
- #include "pycore_dict.h" // export _PyDict_SizeOf()
121
- #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
122
- #include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats()
123
- #include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
124
- #include "pycore_pystate.h" // _PyThreadState_GET()
125
- #include "pycore_setobject.h" // _PySet_NextEntry()
126
- #include "stringlib/eq.h" // unicode_eq()
116
+ #include "pycore_bitutils.h" // _Py_bit_length
117
+ #include "pycore_call.h" // _PyObject_CallNoArgs()
118
+ #include "pycore_ceval.h" // _PyEval_GetBuiltin()
119
+ #include "pycore_code.h" // stats
120
+ #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION, Py_END_CRITICAL_SECTION
121
+ #include "pycore_dict.h" // export _PyDict_SizeOf()
122
+ #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
123
+ #include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats()
124
+ #include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
125
+ #include "pycore_pystate.h" // _PyThreadState_GET()
126
+ #include "pycore_setobject.h" // _PySet_NextEntry()
127
+ #include "stringlib/eq.h" // unicode_eq()
127
128
128
129
#include <stdbool.h>
129
130
@@ -5540,6 +5541,9 @@ make_dict_from_instance_attributes(PyInterpreterState *interp,
5540
5541
track += _PyObject_GC_MAY_BE_TRACKED (val );
5541
5542
}
5542
5543
}
5544
+ // free-threading TODO: We'll need to mark the values to be freed via qsbr
5545
+ // so that a resize doesn't free them immediately while another thread
5546
+ // still has a reference to the old values.
5543
5547
PyObject * res = new_dict (interp , keys , values , used , 0 );
5544
5548
if (track && res ) {
5545
5549
_PyObject_GC_TRACK (res );
@@ -5572,19 +5576,26 @@ _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
5572
5576
return false;
5573
5577
}
5574
5578
assert (_PyType_HasFeature (Py_TYPE (obj ), Py_TPFLAGS_HEAPTYPE ));
5579
+ bool success = true;
5580
+ Py_BEGIN_CRITICAL_SECTION (dict );
5575
5581
if (dict -> ma_keys != CACHED_KEYS (Py_TYPE (obj )) || Py_REFCNT (dict ) != 1 ) {
5576
- return false;
5582
+ success = false;
5583
+ goto exit ;
5577
5584
}
5578
5585
assert (dict -> ma_values );
5579
5586
// We have an opportunity to do something *really* cool: dematerialize it!
5580
5587
_PyDictKeys_DecRef (dict -> ma_keys );
5581
5588
_PyDictOrValues_SetValues (dorv , dict -> ma_values );
5582
5589
OBJECT_STAT_INC (dict_dematerialized );
5590
+ // Lock free readers will need to contend with NULL values here, but
5591
+ // because we locked the dict anyone else will be safe.
5583
5592
// Don't try this at home, kids:
5584
5593
dict -> ma_keys = NULL ;
5585
5594
dict -> ma_values = NULL ;
5586
5595
Py_DECREF (dict );
5587
- return true;
5596
+ exit :
5597
+ Py_END_CRITICAL_SECTION ();
5598
+ return success ;
5588
5599
}
5589
5600
5590
5601
int
0 commit comments