Преглед изворни кода

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

rdb пре 3 месеци
родитељ
комит
b417d6a373

+ 12 - 0
panda/src/event/pythonTask.cxx

@@ -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
 }
 
 /**

+ 8 - 0
panda/src/pgraph/nodePath_ext.cxx

@@ -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()) {

+ 8 - 0
panda/src/pgraph/pandaNode_ext.cxx

@@ -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();
 

+ 17 - 2
panda/src/pstatclient/pStatClient_ext.cxx

@@ -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