backport: A few thread safety things for free-threaded builds

This commit is contained in:
rdb 2025-08-28 11:34:37 +02:00
parent 86ba156a7b
commit b417d6a373
4 changed files with 45 additions and 2 deletions

View File

@ -368,6 +368,17 @@ __getattr__(PyObject *attr) const {
// tp_getattro slot (a la __getattribute__). So, we won't get here when the
// attribute has already been found via other methods.
#if PY_VERSION_HEX >= 0x030D00A1 // 3.13
PyObject *item = nullptr;
if (PyDict_GetItemRef(__dict__, attr, &item) == 0) {
// PyDict_GetItemRef does not raise an exception on missing attribute.
PyErr_Format(PyExc_AttributeError,
"'PythonTask' object has no attribute '%U'",
attr);
}
return item;
#else // 3.12 and lower
PyObject *item = PyDict_GetItem(__dict__, attr);
if (item == nullptr) {
@ -387,6 +398,7 @@ __getattr__(PyObject *attr) const {
// PyDict_GetItem returns a borrowed reference.
Py_INCREF(item);
return item;
#endif
}
/**

View File

@ -55,6 +55,13 @@ PyObject *Extension<NodePath>::
__deepcopy__(PyObject *self, PyObject *memo) const {
extern struct Dtool_PyTypedObject Dtool_NodePath;
#if PY_VERSION_HEX >= 0x030D00A1 // 3.13
PyObject *dupe;
if (PyDict_GetItemRef(memo, self, &dupe) != 0) {
// Already in the memo dictionary (or an error happened).
return dupe;
}
#else
// Borrowed reference.
PyObject *dupe = PyDict_GetItem(memo, self);
if (dupe != nullptr) {
@ -62,6 +69,7 @@ __deepcopy__(PyObject *self, PyObject *memo) const {
Py_INCREF(dupe);
return dupe;
}
#endif
NodePath *np_dupe;
if (_this->is_empty()) {

View File

@ -46,6 +46,13 @@ PyObject *Extension<PandaNode>::
__deepcopy__(PyObject *self, PyObject *memo) const {
extern struct Dtool_PyTypedObject Dtool_PandaNode;
#if PY_VERSION_HEX >= 0x030D00A1 // 3.13
PyObject *dupe;
if (PyDict_GetItemRef(memo, self, &dupe) != 0) {
// Already in the memo dictionary (or an error happened).
return dupe;
}
#else
// Borrowed reference.
PyObject *dupe = PyDict_GetItem(memo, self);
if (dupe != nullptr) {
@ -53,6 +60,7 @@ __deepcopy__(PyObject *self, PyObject *memo) const {
Py_INCREF(dupe);
return dupe;
}
#endif
PT(PandaNode) node_dupe = _this->copy_subgraph();

View File

@ -73,11 +73,21 @@ __declspec(noinline)
make_python_frame_collector(PyFrameObject *frame, PyCodeObject *code) {
#if PY_VERSION_HEX >= 0x030B0000 // 3.11
// Fetch the module name out of the frame's global scope.
const char *mod_name = "<unknown>";
PyObject *py_mod_name = nullptr;
PyObject *globals = PyFrame_GetGlobals(frame);
PyObject *py_mod_name = PyDict_GetItemString(globals, "__name__");
#if PY_VERSION_HEX >= 0x030D00A1 // 3.13
if (PyDict_GetItemStringRef(globals, "__name__", &py_mod_name) > 0) {
mod_name = PyUnicode_AsUTF8(py_mod_name);
}
#else
py_mod_name = PyDict_GetItemString(globals, "__name__");
if (py_mod_name != nullptr) {
mod_name = PyUnicode_AsUTF8(py_mod_name);
}
#endif
Py_DECREF(globals);
const char *mod_name = py_mod_name ? PyUnicode_AsUTF8(py_mod_name) : "<unknown>";
const char *meth_name = PyUnicode_AsUTF8(code->co_qualname);
char buffer[1024];
size_t len = snprintf(buffer, sizeof(buffer), "%s:%s", mod_name, meth_name);
@ -86,6 +96,11 @@ make_python_frame_collector(PyFrameObject *frame, PyCodeObject *code) {
buffer[i] = ':';
}
}
#if PY_VERSION_HEX >= 0x030D00A1 // 3.13
Py_XDECREF(py_mod_name);
#endif
#else
// Try to figure out the type name. There's no obvious way to do this.
// It's possible that the first argument passed to this function is the