diff options
-rw-r--r-- | generator/cppgenerator.cpp | 35 | ||||
-rw-r--r-- | generator/cppgenerator.h | 3 | ||||
-rw-r--r-- | libshiboken/basewrapper.cpp | 35 | ||||
-rw-r--r-- | tests/samplebinding/typedealloc_test.py | 70 |
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() + |