Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit da53660

Browse filesBrowse files
authored
gh-131586: Avoid refcount contention in context managers (gh-131851)
This avoid reference count contention in the free threading build when calling special methods like `__enter__` and `__exit__`.
1 parent 8dfa840 commit da53660
Copy full SHA for da53660

File tree

Expand file treeCollapse file tree

11 files changed

+244
-204
lines changed
Filter options
Expand file treeCollapse file tree

11 files changed

+244
-204
lines changed

‎Include/internal/pycore_object.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_object.h
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ extern int _PyObject_IsInstanceDictEmpty(PyObject *);
950950

951951
// Export for 'math' shared extension
952952
PyAPI_FUNC(PyObject*) _PyObject_LookupSpecial(PyObject *, PyObject *);
953-
PyAPI_FUNC(PyObject*) _PyObject_LookupSpecialMethod(PyObject *self, PyObject *attr, PyObject **self_or_null);
953+
PyAPI_FUNC(int) _PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self);
954954

955955
// Calls the method named `attr` on `self`, but does not set an exception if
956956
// the attribute does not exist.

‎Include/internal/pycore_opcode_metadata.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_opcode_metadata.h
+2-2Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Include/internal/pycore_uop_ids.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_uop_ids.h
+104-103Lines changed: 104 additions & 103 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Include/internal/pycore_uop_metadata.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_uop_metadata.h
+6-2Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Objects/typeobject.c

Copy file name to clipboardExpand all lines: Objects/typeobject.c
+24-19Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,32 +2794,37 @@ _PyObject_LookupSpecial(PyObject *self, PyObject *attr)
27942794
return res;
27952795
}
27962796

2797-
/* Steals a reference to self */
2798-
PyObject *
2799-
_PyObject_LookupSpecialMethod(PyObject *self, PyObject *attr, PyObject **self_or_null)
2797+
// Lookup the method name `attr` on `self`. On entry, `method_and_self[0]`
2798+
// is null and `method_and_self[1]` is `self`. On exit, `method_and_self[0]`
2799+
// is the method object and `method_and_self[1]` is `self` if the method is
2800+
// not bound.
2801+
// Return 1 on success, -1 on error, and 0 if the method is missing.
2802+
int
2803+
_PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self)
28002804
{
2801-
PyObject *res;
2802-
2803-
res = _PyType_LookupRef(Py_TYPE(self), attr);
2804-
if (res == NULL) {
2805-
Py_DECREF(self);
2806-
*self_or_null = NULL;
2807-
return NULL;
2805+
PyObject *self = PyStackRef_AsPyObjectBorrow(method_and_self[1]);
2806+
_PyType_LookupStackRefAndVersion(Py_TYPE(self), attr, &method_and_self[0]);
2807+
PyObject *method_o = PyStackRef_AsPyObjectBorrow(method_and_self[0]);
2808+
if (method_o == NULL) {
2809+
return 0;
28082810
}
28092811

2810-
if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
2812+
if (_PyType_HasFeature(Py_TYPE(method_o), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
28112813
/* Avoid temporary PyMethodObject */
2812-
*self_or_null = self;
2814+
return 1;
28132815
}
2814-
else {
2815-
descrgetfunc f = Py_TYPE(res)->tp_descr_get;
2816-
if (f != NULL) {
2817-
Py_SETREF(res, f(res, self, (PyObject *)(Py_TYPE(self))));
2816+
2817+
descrgetfunc f = Py_TYPE(method_o)->tp_descr_get;
2818+
if (f != NULL) {
2819+
PyObject *func = f(method_o, self, (PyObject *)(Py_TYPE(self)));
2820+
if (func == NULL) {
2821+
return -1;
28182822
}
2819-
*self_or_null = NULL;
2820-
Py_DECREF(self);
2823+
PyStackRef_CLEAR(method_and_self[0]); // clear method
2824+
method_and_self[0] = PyStackRef_FromPyObjectSteal(func);
28212825
}
2822-
return res;
2826+
PyStackRef_CLEAR(method_and_self[1]); // clear self
2827+
return 1;
28232828
}
28242829

28252830
static int

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.