aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generator/cppgenerator.cpp35
-rw-r--r--generator/cppgenerator.h3
-rw-r--r--libshiboken/basewrapper.cpp35
-rw-r--r--tests/samplebinding/typedealloc_test.py70
4 files changed, 130 insertions, 13 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp
index dbc2a9456..c26536a1c 100644
--- a/generator/cppgenerator.cpp
+++ b/generator/cppgenerator.cpp
@@ -540,6 +540,11 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl
if (!metaClass->typeEntry()->hashFunction().isEmpty())
writeHashFunction(s, metaClass);
+
+ // Write tp_traverse and tp_clear functions.
+ writeTpTraverseFunction(s, metaClass);
+ writeTpClearFunction(s, metaClass);
+
writeClassDefinition(s, metaClass);
s << endl;
@@ -2540,15 +2545,15 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass*
bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
- tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES";
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC";
tp_dealloc = metaClass->hasPrivateDestructor() ?
"SbkDeallocWrapperWithPrivateDtor" : "0";
tp_init = "0";
} else {
if (onlyPrivCtor)
- tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES";
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC";
else
- tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES";
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC";
QString deallocClassName;
if (shouldGenerateCppWrapper(metaClass))
@@ -2635,8 +2640,8 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass*
s << INDENT << "/*tp_as_buffer*/ 0," << endl;
s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl;
s << INDENT << "/*tp_doc*/ 0," << endl;
- s << INDENT << "/*tp_traverse*/ 0," << endl;
- s << INDENT << "/*tp_clear*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl;
+ s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl;
s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl;
s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
s << INDENT << "/*tp_iter*/ " << m_tpFuncs["__iter__"] << ',' << endl;
@@ -2836,6 +2841,26 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet
s << INDENT << baseName << "_Type.super.as_number.nb_true_divide = " << nb["__div__"] << ';' << endl;
}
+void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int ";
+ s << baseName << "_traverse(PyObject* self, visitproc visit, void* arg)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_traverse(self, visit, arg);" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int ";
+ s << baseName << "_clear(PyObject* self)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_clear(self);" << endl;
+ s << '}' << endl;
+}
+
void CppGenerator::writeCopyFunction(QTextStream& s, const AbstractMetaClass *metaClass)
{
QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), "");
diff --git a/generator/cppgenerator.h b/generator/cppgenerator.h
index 485c42361..a5709ec52 100644
--- a/generator/cppgenerator.h
+++ b/generator/cppgenerator.h
@@ -142,6 +142,9 @@ private:
void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
void writeCopyFunction(QTextStream& s, const AbstractMetaClass *metaClass);
void writeGetterFunction(QTextStream& s, const AbstractMetaField* metaField);
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp
index a34ef1fef..3ea0507ef 100644
--- a/libshiboken/basewrapper.cpp
+++ b/libshiboken/basewrapper.cpp
@@ -76,9 +76,9 @@ PyTypeObject SbkObjectType_Type = {
/*tp_descr_set*/ 0,
/*tp_dictoffset*/ 0,
/*tp_init*/ 0,
- /*tp_alloc*/ 0,
+ /*tp_alloc*/ PyType_GenericAlloc,
/*tp_new*/ SbkObjectTypeTpNew,
- /*tp_free*/ 0,
+ /*tp_free*/ PyObject_GC_Del,
/*tp_is_gc*/ 0,
/*tp_bases*/ 0,
/*tp_mro*/ 0,
@@ -102,6 +102,22 @@ static PyGetSetDef SbkObjectGetSetList[] = {
{0} // Sentinel
};
+static int SbkObject_traverse(PyObject* self, visitproc visit, void* arg)
+{
+ SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self);
+ if (sbkSelf->ob_dict)
+ Py_VISIT(sbkSelf->ob_dict);
+ return 0;
+}
+
+static int SbkObject_clear(PyObject* self)
+{
+ SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self);
+ if (sbkSelf->ob_dict)
+ Py_CLEAR(sbkSelf->ob_dict);
+ return 0;
+}
+
SbkObjectType SbkObject_Type = { { {
PyObject_HEAD_INIT(&SbkObjectType_Type)
/*ob_size*/ 0,
@@ -123,10 +139,10 @@ SbkObjectType SbkObject_Type = { { {
/*tp_getattro*/ 0,
/*tp_setattro*/ 0,
/*tp_as_buffer*/ 0,
- /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
/*tp_doc*/ 0,
- /*tp_traverse*/ 0,
- /*tp_clear*/ 0,
+ /*tp_traverse*/ SbkObject_traverse,
+ /*tp_clear*/ SbkObject_clear,
/*tp_richcompare*/ 0,
/*tp_weaklistoffset*/ offsetof(SbkObject, weakreflist),
/*tp_iter*/ 0,
@@ -188,9 +204,9 @@ void SbkDeallocWrapperWithPrivateDtor(PyObject* self)
void SbkObjectTypeDealloc(PyObject* pyObj)
{
SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyObj);
- if (!sbkType->d)
- return;
+ PyObject_GC_UnTrack(pyObj);
+ Py_TRASHCAN_SAFE_BEGIN(pyObj);
if(sbkType->d->user_data && sbkType->d->d_func) {
sbkType->d->d_func(sbkType->d->user_data);
sbkType->d->user_data = 0;
@@ -199,6 +215,7 @@ void SbkObjectTypeDealloc(PyObject* pyObj)
sbkType->d->original_name = 0;
delete sbkType->d;
sbkType->d = 0;
+ Py_TRASHCAN_SAFE_END(pyObj);
}
PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds)
@@ -275,7 +292,8 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*)
{
- SbkObject* self = reinterpret_cast<SbkObject*>(subtype->tp_alloc(subtype, 0));
+ SbkObject* self = PyObject_GC_New(SbkObject, subtype);
+ Py_INCREF(reinterpret_cast<PyObject*>(subtype));
SbkObjectPrivate* d = new SbkObjectPrivate;
SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(subtype);
@@ -291,6 +309,7 @@ PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*)
self->ob_dict = 0;
self->weakreflist = 0;
self->d = d;
+ PyObject_GC_Track(reinterpret_cast<PyObject*>(self));
return reinterpret_cast<PyObject*>(self);
}
diff --git a/tests/samplebinding/typedealloc_test.py b/tests/samplebinding/typedealloc_test.py
new file mode 100644
index 000000000..c9f6d4998
--- /dev/null
+++ b/tests/samplebinding/typedealloc_test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# This file is part of the Shiboken Python Bindings Generator project.
+#
+# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+#
+# Contact: PySide team <contact@pyside.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# version 2.1 as published by the Free Software Foundation. Please
+# review the following information to ensure the GNU Lesser General
+# Public License version 2.1 requirements will be met:
+# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+# #
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+'''Test deallocation of type extended in Python.'''
+
+import gc
+import weakref
+import unittest
+
+from sample import Point
+
+
+class TypeDeallocTest(unittest.TestCase):
+
+ def setUp(self):
+ self.called = False
+
+ def tearDown(self):
+ del self.called
+
+ def callback(self, *args):
+ self.called = True
+
+ def testScopeEnd(self):
+ ref = None
+ def scope():
+ class Ext(Point):
+ pass
+ o = Ext()
+ global ref
+ ref = weakref.ref(Ext, self.callback)
+ scope()
+ gc.collect()
+ self.assert_(self.called)
+
+ def testDeleteType(self):
+ class Ext(Point):
+ pass
+ ref = weakref.ref(Ext, self.callback)
+ del Ext
+ gc.collect()
+ self.assert_(self.called)
+
+
+if __name__ == '__main__':
+ unittest.main()
+