Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/python/intern/bpy_rna.c150
-rw-r--r--source/blender/python/intern/bpy_rna.h19
2 files changed, 163 insertions, 6 deletions
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index bc216207821..b1338f3b82d 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -37,11 +37,19 @@
#include "bpy_util.h"
#include "bpy_rna_callback.h"
+#ifdef USE_PYRNA_INVALIDATE_GC
+#include "MEM_guardedalloc.h"
+#endif
+
#include "BLI_dynstr.h"
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
+#ifdef USE_PYRNA_INVALIDATE_GC
+#include "BLI_ghash.h"
+#endif
+
#include "RNA_enum_types.h"
#include "RNA_define.h" /* RNA_def_property_free_identifier */
@@ -134,13 +142,138 @@ static void id_release_gc(struct ID *id)
}
#endif
+#ifdef USE_PYRNA_INVALIDATE_WEAKREF
+struct GHash *id_weakref_pool= NULL;
+static PyObject *id_free_weakref_cb(PyObject *weakinfo_pair, PyObject *weakref);
+static PyMethodDef id_free_weakref_cb_def= {"id_free_weakref_cb", (PyCFunction)id_free_weakref_cb, METH_O, NULL};
+
+/* adds a reference to the list, remember ot decref */
+static PyObject *id_weakref_pool_get(ID *id)
+{
+ PyObject *weakinfo_list= NULL;
+
+ if(id_weakref_pool) {
+ weakinfo_list= BLI_ghash_lookup(id_weakref_pool, (void *)id);
+ }
+ else {
+ /* first time, allocate pool */
+ id_weakref_pool= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "copyArc gh");
+ weakinfo_list= NULL;
+ }
+
+ if(weakinfo_list==NULL) {
+ weakinfo_list= PyList_New(0);
+ BLI_ghash_insert(id_weakref_pool, (void *)id, weakinfo_list);
+ }
+
+ return weakinfo_list;
+}
+
+/* called from pyrna_struct_CreatePyObject() and pyrna_prop_CreatePyObject() */
+void id_weakref_pool_add(ID *id, BPy_DummyPointerRNA* pyrna)
+{
+ PyObject *weakref;
+ PyObject *weakref_cb_py;
+
+ /* create a new function instance and insert the list as 'self' so we can remove ourself from it */
+ PyObject *weakinfo_list= id_weakref_pool_get(id); /* new or existing */
+ PyObject *weakinfo_pair= PyTuple_New(2);
+ PyTuple_SET_ITEM(weakinfo_pair, 0, weakinfo_list);
+ Py_INCREF(weakinfo_list);
+ PyTuple_SET_ITEM(weakinfo_pair, 1, PyCapsule_New(id, NULL, NULL));
+ weakref_cb_py= PyCFunction_New(&id_free_weakref_cb_def, weakinfo_pair);
+ Py_DECREF(weakinfo_pair); /* function' 'self' now owns weakinfo_list now */
+
+ /* add weakref to weakinfo_list list */
+ weakref= PyWeakref_NewRef((PyObject *)pyrna, weakref_cb_py);
+ Py_DECREF(weakref_cb_py); /* function owned by the weakref now */
+
+ /* important to add at the end, since first removal looks at the end */
+ PyList_Append(weakinfo_list, weakref);
+ Py_DECREF(weakref);
+}
+
+static void id_release_weakref(struct ID *id);
+static PyObject *id_free_weakref_cb(PyObject *weakinfo_pair, PyObject *weakref)
+{
+
+ /* important to search backwards */
+ PyObject *weakinfo_list= PyTuple_GET_ITEM(weakinfo_pair, 0);
+ unsigned int i= PyList_GET_SIZE(weakinfo_list);
+ const unsigned int last_index= i - 1;
+
+ while(i--) {
+ if(PyList_GET_ITEM(weakinfo_list, i) == weakref) {
+ /* swap */
+ if(i != last_index) {
+ PyList_SET_ITEM(weakinfo_list, i, PyList_GET_ITEM(weakinfo_list, last_index));
+ }
+ PyList_SET_ITEM(weakinfo_list, last_index, NULL); /* to avoid weakref issue */
+ /* remove last item */
+ PyList_SetSlice(weakinfo_list, last_index, PY_SSIZE_T_MAX, NULL);
+ Py_DECREF(weakref);
+
+/*DEBUG*/ //printf("bprna_weakref_cb: %p size is %d\n", weakref, last_index + 1);
+
+ /* optional, free the list once its 0 size
+ * to keep the ID hash lookups fast by not allowing manu empty items to exist */
+ if(last_index == 0) {
+ PyObject *weakinfo_id= PyTuple_GET_ITEM(weakinfo_pair, 1);
+ ID *id= PyCapsule_GetPointer(weakinfo_id, NULL);
+
+ /* the list is empty, just free it */
+ id_release_weakref(id);
+ }
+ break;
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static void id_release_weakref(struct ID *id)
+{
+ PyObject *weakinfo_list= BLI_ghash_lookup(id_weakref_pool, (void *)id);
+ if(weakinfo_list) {
+ unsigned int i= PyList_GET_SIZE(weakinfo_list);
+
+/*DEBUG*/ //printf("BPY_id_release: '%s', %d items\n", id->name, i);
+
+ while(i--) {
+ PyObject *item= PyWeakref_GET_OBJECT(PyList_GET_ITEM(weakinfo_list, i));
+ if(item != Py_None) {
+ pyrna_invalidate((BPy_DummyPointerRNA *)item);
+ }
+ }
+
+ BLI_ghash_remove(id_weakref_pool, (void *)id, NULL, NULL);
+ Py_DECREF(weakinfo_list);
+
+ if(BLI_ghash_size(id_weakref_pool) == 0) {
+/*DEBUG*/ //printf("BPY_id_release: freeing global pool\n");
+ BLI_ghash_free(id_weakref_pool, NULL, NULL);
+ id_weakref_pool= NULL;
+ }
+ }
+}
+
+#endif /* USE_PYRNA_INVALIDATE_WEAKREF */
void BPY_id_release(struct ID *id)
{
- (void)id;
#ifdef USE_PYRNA_INVALIDATE_GC
id_release_gc(id);
#endif
+
+#ifdef USE_PYRNA_INVALIDATE_WEAKREF
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ id_release_weakref(id);
+
+ PyGILState_Release(gilstate);
+#endif /* USE_PYRNA_INVALIDATE_WEAKREF */
+
+ (void)id;
}
#ifdef USE_PEDANTIC_WRITE
@@ -5080,7 +5213,12 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr )
pyrna->freeptr= FALSE;
// PyC_ObSpit("NewStructRNA: ", (PyObject *)pyrna);
-
+
+#ifdef USE_PYRNA_INVALIDATE_WEAKREF
+ if(ptr->id.data) {
+ id_weakref_pool_add(ptr->id.data, (BPy_DummyPointerRNA *)pyrna);
+ }
+#endif
return ( PyObject * ) pyrna;
}
@@ -5124,7 +5262,13 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop )
pyrna->ptr = *ptr;
pyrna->prop = prop;
-
+
+#ifdef USE_PYRNA_INVALIDATE_WEAKREF
+ if(ptr->id.data) {
+ id_weakref_pool_add(ptr->id.data, (BPy_DummyPointerRNA *)pyrna);
+ }
+#endif
+
return ( PyObject * ) pyrna;
}
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index 8d9fabf5627..be877344c48 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -44,12 +44,25 @@ extern PyTypeObject pyrna_prop_collection_Type;
#define BPy_PropertyRNA_Check(v) (PyObject_TypeCheck(v, &pyrna_prop_Type))
#define BPy_PropertyRNA_CheckExact(v) (Py_TYPE(v) == &pyrna_prop_Type)
-/* method to invalidate removed py data, XXX, slow to remove objects, otherwise no overhead */
-// #define USE_PYRNA_INVALIDATE_GC
-
/* play it safe and keep optional for now, need to test further now this affects looping on 10000's of verts for eg. */
// #define USE_WEAKREFS
+/* method to invalidate removed py data, XXX, slow to remove objects, otherwise no overhead */
+//#define USE_PYRNA_INVALIDATE_GC
+
+/* different method */
+//#define USE_PYRNA_INVALIDATE_WEAKREF
+
+
+/* sanity checks on above defs */
+#if defined(USE_PYRNA_INVALIDATE_WEAKREF) && !defined(USE_WEAKREFS)
+#define USE_WEAKREFS
+#endif
+
+#if defined(USE_PYRNA_INVALIDATE_GC) && defined(USE_PYRNA_INVALIDATE_WEAKREF)
+#error "Only 1 reference check method at a time!"
+#endif
+
typedef struct {
PyObject_HEAD /* required python macro */
PointerRNA ptr;