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:
authorCampbell Barton <ideasman42@gmail.com>2011-03-03 12:16:06 +0300
committerCampbell Barton <ideasman42@gmail.com>2011-03-03 12:16:06 +0300
commitb6b77b8426318a8f02f3f01c8cd9abe799843470 (patch)
tree2c0f9af708583e615edc0dab0d3ec55b7a49ae5d /source/blender/python
parent57436f3013998ffff24625d5c8bf96e865fbe022 (diff)
Py/RNA api:
fix for crash when iterating over a collection which allocates the collection and frees on when finished. The ability for BPy_StructRNA to hold a reference to other PyObject's was added to support this.
Diffstat (limited to 'source/blender/python')
-rw-r--r--source/blender/python/intern/bpy_rna.c62
-rw-r--r--source/blender/python/intern/bpy_rna.h8
2 files changed, 66 insertions, 4 deletions
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 121407bcb70..0009c5f7f47 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -900,6 +900,20 @@ static long pyrna_prop_hash(BPy_PropertyRNA *self)
return x;
}
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+static int pyrna_struct_traverse(BPy_StructRNA *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->reference);
+ return 0;
+}
+
+static int pyrna_struct_clear(BPy_StructRNA *self)
+{
+ Py_CLEAR(self->reference);
+ return 0;
+}
+#endif /* !USE_PYRNA_STRUCT_REFERENCE */
+
/* use our own dealloc so we can free a property if we use one */
static void pyrna_struct_dealloc(BPy_StructRNA *self)
{
@@ -915,10 +929,34 @@ static void pyrna_struct_dealloc(BPy_StructRNA *self)
}
#endif
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ if(self->reference) {
+ PyObject_GC_UnTrack(self);
+ pyrna_struct_clear(self);
+ }
+#endif /* !USE_PYRNA_STRUCT_REFERENCE */
+
/* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */
Py_TYPE(self)->tp_free(self);
}
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+static void pyrna_struct_reference_set(BPy_StructRNA *self, PyObject *reference)
+{
+ if(self->reference) {
+// PyObject_GC_UnTrack(self); /* INITIALIZED TRACKED? */
+ pyrna_struct_clear(self);
+ }
+ /* reference is now NULL */
+
+ if(reference) {
+ self->reference= reference;
+ Py_INCREF(reference);
+// PyObject_GC_Track(self); /* INITIALIZED TRACKED? */
+ }
+}
+#endif /* !USE_PYRNA_STRUCT_REFERENCE */
+
/* use our own dealloc so we can free a property if we use one */
static void pyrna_prop_dealloc(BPy_PropertyRNA *self)
{
@@ -4312,15 +4350,22 @@ PyTypeObject pyrna_struct_Type = {
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* long tp_flags; */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
- NULL, /* traverseproc tp_traverse; */
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ (traverseproc) pyrna_struct_traverse, /* traverseproc tp_traverse; */
/* delete references to contained objects */
+ (inquiry )pyrna_struct_clear, /* inquiry tp_clear; */
+#else
+ NULL, /* traverseproc tp_traverse; */
+
+/* delete references to contained objects */
NULL, /* inquiry tp_clear; */
+#endif /* !USE_PYRNA_STRUCT_REFERENCE */
/*** Assigned meaning in release 2.1 ***/
/*** rich comparisons ***/
@@ -4817,11 +4862,16 @@ static PyObject *pyrna_prop_collection_iter_next(BPy_PropertyCollectionIterRNA *
else {
BPy_StructRNA *pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&self->iter.ptr);
+#ifdef USE_PYRNA_STRUCT_REFERENCE
if(pyrna) { /* unlikely but may fail */
if((PyObject *)pyrna != Py_None) {
- // pyrna->reference;
+ /* hold a reference to the iterator since it may have
+ * allocated memory 'pyrna' needs. eg: introspecting dynamic enum's */
+ /* TODO, we could have an api call to know if this is needed since most collections don't */
+ pyrna_struct_reference_set(pyrna, (PyObject *)self);
}
}
+#endif /* !USE_PYRNA_STRUCT_REFERENCE */
RNA_property_collection_next(&self->iter);
@@ -5055,7 +5105,7 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr)
}
else {
fprintf(stderr, "Could not make type\n");
- pyrna = (BPy_StructRNA *) PyObject_NEW(BPy_StructRNA, &pyrna_struct_Type);
+ pyrna = (BPy_StructRNA *) PyObject_GC_New(BPy_StructRNA, &pyrna_struct_Type);
#ifdef USE_WEAKREFS
pyrna->in_weakreflist= NULL;
#endif
@@ -5070,6 +5120,10 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr)
pyrna->ptr= *ptr;
pyrna->freeptr= FALSE;
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ pyrna->reference= NULL;
+#endif
+
// PyC_ObSpit("NewStructRNA: ", (PyObject *)pyrna);
#ifdef USE_PYRNA_INVALIDATE_WEAKREF
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index 9c2b2b62ff8..b5da9bf91be 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -40,6 +40,9 @@
/* different method */
//#define USE_PYRNA_INVALIDATE_WEAKREF
+/* support for inter references, currently only needed for corner case */
+// #define USE_PYRNA_STRUCT_REFERENCE
+
/* use real collection iterators rather then faking with a list */
#define USE_PYRNA_ITER
@@ -90,6 +93,11 @@ typedef struct {
PyObject *in_weakreflist;
#endif
PointerRNA ptr;
+#ifdef USE_PYRNA_STRUCT_REFERENCE
+ /* generic PyObject we hold a reference to, example use:
+ * hold onto the collection iterator to prevent it from freeing allocated data we may use */
+ PyObject *reference;
+#endif /* !USE_PYRNA_STRUCT_REFERENCE */
int freeptr; /* needed in some cases if ptr.data is created on the fly, free when deallocing */
} BPy_StructRNA;