8000 gh-112075: Make some `dict` operations thread-safe without GIL by chgnrdv · Pull Request #112247 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-112075: Make some dict operations thread-safe without GIL #112247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
make dict.__repr__ thread-safe with critical section API macro
  • Loading branch information
chgnrdv committed Nov 18, 2023
commit fa6aada6696ce7389f0de8111cd3d9dd5156f8fc
40 changes: 22 additions & 18 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2506,15 +2506,18 @@ dict_repr(PyDictObject *mp)
PyObject *key = NULL, *value = NULL;
_PyUnicodeWriter writer;
int first;
PyObject *repr = NULL;

i = Py_ReprEnter((PyObject *)mp);
if (i != 0) {
return i > 0 ? PyUnicode_FromString("{...}") : NULL;
}

Py_BEGIN_CRITICAL_SECTION(mp);

if (mp->ma_used == 0) {
Py_ReprLeave((PyObject *)mp);
return PyUnicode_FromString("{}");
repr = PyUnicode_FromString("{}");
goto end;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thin this may incorrectly call _PyUnicodeWriter_Dealloc() on an uninitialized writer below if repr is NULL (i.e., if PyUnicode_FromString returns an error).

For these functions with complex control flow, I think it's better to add a wrapper function than try to work Py_BEGIN_CRITICAL_SECTION() calls into the existing control flow. In other words:

  • Rename dict_repr to e.g. dict_repr_impl.
  • Add a new dict_repr that just calls dict_repr_impl under a Py_BEGIN_CRITICAL_SECTION() calls.

}

_PyUnicodeWriter_Init(&writer);
Expand All @@ -2523,7 +2526,7 @@ dict_repr(PyDictObject *mp)
writer.min_length = 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1;

if (_PyUnicodeWriter_WriteChar(&writer, '{') < 0)
goto error;
goto end;

/* Do repr() on each key+value pair, and insert ": " between them.
Note that repr may mutate the dict. */
Expand All @@ -2539,47 +2542,48 @@ dict_repr(PyDictObject *mp)

if (!first) {
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
goto error;
goto end;
}
first = 0;

s = PyObject_Repr(key);
if (s == NULL)
goto error;
goto end;
res = _PyUnicodeWriter_WriteStr(&writer, s);
Py_DECREF(s);
if (res < 0)
goto error;
goto end;

if (_PyUnicodeWriter_WriteASCIIString(&writer, ": ", 2) < 0)
goto error;
goto end;

s = PyObject_Repr(value);
if (s == NULL)
goto error;
goto end;
res = _PyUnicodeWriter_WriteStr(&writer, s);
Py_DECREF(s);
if (res < 0)
goto error;
goto end;

Py_CLEAR(key);
Py_CLEAR(value);
}

writer.overallocate = 0;
if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0)
goto error;

Py_ReprLeave((PyObject *)mp);
goto end;

return _PyUnicodeWriter_Finish(&writer);
repr = _PyUnicodeWriter_Finish(&writer);

error:
end:
Py_ReprLeave((PyObject *)mp);
_PyUnicodeWriter_Dealloc(&writer);
Py_XDECREF(key);
Py_XDECREF(value);
return NULL;
if (repr == NULL) {
_PyUnicodeWriter_Dealloc(&writer);
Py_XDECREF(key);
Py_XDECREF(value);
}
Py_END_CRITICAL_SECTION();
return repr;
}

static Py_ssize_t
Expand Down
0