mirror of
https://github.com/samba-team/samba.git
synced 2025-03-27 22:50:26 +03:00
pytalloc: Add new BaseObject
This new object not only avoids the ABI issues of talloc.Object it stores one more pointer, being the start of the array, and so can be used to fix the PIDL bindings/talloc refcount issue. Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Garming Sam <garming@catalyst.net.nz>
This commit is contained in:
parent
528dce1b53
commit
80f2b36efb
@ -20,6 +20,7 @@
|
||||
#include <Python.h>
|
||||
#include <talloc.h>
|
||||
#include <pytalloc.h>
|
||||
#include "pytalloc_private.h"
|
||||
|
||||
static PyTypeObject TallocObject_Type;
|
||||
|
||||
@ -157,6 +158,86 @@ static PyTypeObject TallocObject_Type = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Default (but only slightly more useful than the default) implementation of Repr().
|
||||
*/
|
||||
static PyObject *pytalloc_base_default_repr(PyObject *obj)
|
||||
{
|
||||
pytalloc_BaseObject *talloc_obj = (pytalloc_BaseObject *)obj;
|
||||
PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
|
||||
|
||||
return PyStr_FromFormat("<%s talloc based object at 0x%p>",
|
||||
type->tp_name, talloc_obj->ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple dealloc for talloc-wrapping PyObjects
|
||||
*/
|
||||
static void pytalloc_base_dealloc(PyObject* self)
|
||||
{
|
||||
pytalloc_BaseObject *obj = (pytalloc_BaseObject *)self;
|
||||
assert(talloc_unlink(NULL, obj->talloc_ctx) != -1);
|
||||
obj->talloc_ctx = NULL;
|
||||
self->ob_type->tp_free(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default (but only slightly more useful than the default) implementation of cmp.
|
||||
*/
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static PyObject *pytalloc_base_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
|
||||
{
|
||||
void *ptr1;
|
||||
void *ptr2;
|
||||
if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
|
||||
/* When types match, compare pointers */
|
||||
ptr1 = pytalloc_get_ptr(obj1);
|
||||
ptr2 = pytalloc_get_ptr(obj2);
|
||||
} else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
|
||||
/* Otherwise, compare types */
|
||||
ptr1 = Py_TYPE(obj1);
|
||||
ptr2 = Py_TYPE(obj2);
|
||||
} else {
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
switch (op) {
|
||||
case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
|
||||
case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
|
||||
case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
|
||||
case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
|
||||
case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
|
||||
case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
|
||||
}
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
#else
|
||||
static int pytalloc_base_default_cmp(PyObject *_obj1, PyObject *_obj2)
|
||||
{
|
||||
pytalloc_BaseObject *obj1 = (pytalloc_BaseObject *)_obj1,
|
||||
*obj2 = (pytalloc_BaseObject *)_obj2;
|
||||
if (obj1->ob_type != obj2->ob_type)
|
||||
return ((char *)obj1->ob_type - (char *)obj2->ob_type);
|
||||
|
||||
return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2));
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyTypeObject TallocBaseObject_Type = {
|
||||
.tp_name = "talloc.BaseObject",
|
||||
.tp_doc = "Python wrapper for a talloc-maintained object.",
|
||||
.tp_basicsize = sizeof(pytalloc_BaseObject),
|
||||
.tp_dealloc = (destructor)pytalloc_base_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.tp_repr = pytalloc_base_default_repr,
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
.tp_richcompare = pytalloc_base_default_richcmp,
|
||||
#else
|
||||
.tp_compare = pytalloc_base_default_cmp,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
@ -177,6 +258,9 @@ static PyObject *module_init(void)
|
||||
if (PyType_Ready(&TallocObject_Type) < 0)
|
||||
return NULL;
|
||||
|
||||
if (PyType_Ready(&TallocBaseObject_Type) < 0)
|
||||
return NULL;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
m = PyModule_Create(&moduledef);
|
||||
#else
|
||||
@ -187,6 +271,8 @@ static PyObject *module_init(void)
|
||||
|
||||
Py_INCREF(&TallocObject_Type);
|
||||
PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
|
||||
Py_INCREF(&TallocBaseObject_Type);
|
||||
PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -26,15 +26,20 @@
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
TALLOC_CTX *talloc_ctx;
|
||||
void *ptr;
|
||||
void *ptr; /* eg the array element */
|
||||
} pytalloc_Object;
|
||||
|
||||
/* Return the PyTypeObject for pytalloc_Object. Returns a new reference. */
|
||||
PyTypeObject *pytalloc_GetObjectType(void);
|
||||
|
||||
/* Return the PyTypeObject for pytalloc_BaseObject. Returns a new reference. */
|
||||
PyTypeObject *pytalloc_GetBaseObjectType(void);
|
||||
|
||||
/* Check whether a specific object is a talloc Object. */
|
||||
int pytalloc_Check(PyObject *);
|
||||
|
||||
int pytalloc_BaseObject_check(PyObject *);
|
||||
|
||||
/* Retrieve the pointer for a pytalloc_object. Like talloc_get_type()
|
||||
* but for pytalloc_Objects. */
|
||||
void *_pytalloc_get_type(PyObject *py_obj, const char *type_name);
|
||||
@ -56,4 +61,7 @@ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void
|
||||
PyObject *pytalloc_CObject_FromTallocPtr(void *);
|
||||
#endif
|
||||
|
||||
size_t pytalloc_BaseObject_size(void);
|
||||
|
||||
|
||||
#endif /* _PYTALLOC_H_ */
|
||||
|
@ -29,7 +29,7 @@ Python's PEP3149 ABI tag, for example "pytalloc.cpython34m".
|
||||
To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
|
||||
.
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
pytalloc_Object
|
||||
pytalloc_Object / pytalloc_BaseObject
|
||||
|
||||
This is the new base class that all Python objects that wrap talloc pointers
|
||||
derive from. It is itself a subclass of the "Object" type that all objects
|
||||
@ -53,6 +53,10 @@ compares the pointers the object is wrapping rather than the objects
|
||||
themselves (since there can be multiple objects that wrap the same talloc
|
||||
pointer).
|
||||
|
||||
It is preferred to use pytalloc_BaseObject as this implementation
|
||||
exposes less in the C ABI and correctly supports pointers in C arrays
|
||||
in the way needed by PIDL.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
PyTypeObject *pytalloc_GetObjectType(void)
|
||||
|
||||
@ -60,12 +64,25 @@ Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference
|
||||
counter for the object will be incremented, so the caller will have to
|
||||
decrement it when it no longer needs it (using `Py_DECREF`).
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
PyTypeObject *pytalloc_GetBaseObjectType(void)
|
||||
|
||||
Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference
|
||||
counter for the object will be incremented, so the caller will have to
|
||||
decrement it when it no longer needs it (using `Py_DECREF`).
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
|
||||
int pytalloc_Check(PyObject *)
|
||||
|
||||
Check whether a specific object is a talloc Object. Returns non-zero if it is
|
||||
a pytalloc_Object and zero otherwise.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
|
||||
int pytalloc_BaseObject_Check(PyObject *)
|
||||
|
||||
Check whether a specific object is a talloc BaseObject. Returns non-zero if it is
|
||||
a pytalloc_BaseObject and zero otherwise.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
type *pytalloc_get_type(PyObject *py_obj, type)
|
||||
|
||||
@ -75,13 +92,14 @@ C type, similar to a type passed to `talloc_get_type`.
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
pytalloc_get_ptr(PyObject *py_obj)
|
||||
|
||||
Retrieve the pointer from a `pytalloc_Object` py_obj. There is no
|
||||
type checking - use `pytalloc_get_type` if possible.
|
||||
Retrieve the pointer from a `pytalloc_Object` or `pytalloc_BaseObject`
|
||||
py_obj. There is no type checking - use `pytalloc_get_type` if
|
||||
possible.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj)
|
||||
|
||||
Retrieve the talloc context associated with a pytalloc_Object.
|
||||
Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseObject.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
|
||||
|
26
lib/talloc/pytalloc_private.h
Normal file
26
lib/talloc/pytalloc_private.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
TALLOC_CTX *talloc_ctx;
|
||||
TALLOC_CTX *talloc_ptr_ctx; /* eg the start of the array */
|
||||
void *ptr; /* eg the array element */
|
||||
} pytalloc_BaseObject;
|
@ -22,6 +22,7 @@
|
||||
#include <talloc.h>
|
||||
#include "pytalloc.h"
|
||||
#include <assert.h>
|
||||
#include "pytalloc_private.h"
|
||||
|
||||
_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
|
||||
{
|
||||
@ -43,23 +44,82 @@ _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
|
||||
return type;
|
||||
}
|
||||
|
||||
_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
|
||||
{
|
||||
static PyTypeObject *type = NULL;
|
||||
PyObject *mod;
|
||||
|
||||
if (type != NULL) {
|
||||
return type;
|
||||
}
|
||||
|
||||
mod = PyImport_ImportModule("talloc");
|
||||
if (mod == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
|
||||
Py_DECREF(mod);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import an existing talloc pointer into a Python object.
|
||||
*/
|
||||
_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
|
||||
void *ptr)
|
||||
void *ptr)
|
||||
{
|
||||
pytalloc_Object *ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
|
||||
ret->talloc_ctx = talloc_new(NULL);
|
||||
if (ret->talloc_ctx == NULL) {
|
||||
PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
|
||||
PyTypeObject *ObjectType = pytalloc_GetObjectType();
|
||||
|
||||
if (mem_ctx == NULL) {
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
if (PyType_IsSubtype(py_type, BaseObjectType)) {
|
||||
pytalloc_BaseObject *ret
|
||||
= (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
|
||||
|
||||
ret->talloc_ctx = talloc_new(NULL);
|
||||
if (ret->talloc_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This allows us to keep multiple references to this object -
|
||||
* we only reference this context, which is per ptr, not the
|
||||
* talloc_ctx, which is per pytalloc_Object
|
||||
*/
|
||||
if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->talloc_ptr_ctx = mem_ctx;
|
||||
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
|
||||
ret->ptr = ptr;
|
||||
return (PyObject *)ret;
|
||||
|
||||
} else if (PyType_IsSubtype(py_type, ObjectType)) {
|
||||
pytalloc_Object *ret
|
||||
= (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
|
||||
|
||||
ret->talloc_ctx = talloc_new(NULL);
|
||||
if (ret->talloc_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
|
||||
ret->ptr = ptr;
|
||||
return (PyObject *)ret;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"pytalloc_steal_ex() called for object type "
|
||||
"not based on talloc");
|
||||
return NULL;
|
||||
}
|
||||
if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
|
||||
ret->ptr = ptr;
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,27 +134,57 @@ _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
|
||||
/**
|
||||
* Import an existing talloc pointer into a Python object, leaving the
|
||||
* original parent, and creating a reference to the object in the python
|
||||
* object
|
||||
* object.
|
||||
*
|
||||
* We remember the object we hold the reference to (a
|
||||
* possibly-non-talloc pointer), the existing parent (typically the
|
||||
* start of the array) and the new referenced parent. That way we can
|
||||
* cope with the fact that we will have multiple parents, one per time
|
||||
* python sees the object.
|
||||
*/
|
||||
_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
|
||||
_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
|
||||
TALLOC_CTX *mem_ctx, void *ptr)
|
||||
{
|
||||
pytalloc_Object *ret;
|
||||
PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
|
||||
PyTypeObject *ObjectType = pytalloc_GetObjectType();
|
||||
|
||||
if (ptr == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
if (mem_ctx == NULL) {
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
|
||||
ret->talloc_ctx = talloc_new(NULL);
|
||||
if (ret->talloc_ctx == NULL) {
|
||||
if (PyType_IsSubtype(py_type, BaseObjectType)) {
|
||||
pytalloc_BaseObject *ret
|
||||
= (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
|
||||
ret->talloc_ctx = talloc_new(NULL);
|
||||
if (ret->talloc_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
|
||||
ret->talloc_ptr_ctx = mem_ctx;
|
||||
ret->ptr = ptr;
|
||||
return (PyObject *)ret;
|
||||
} else if (PyType_IsSubtype(py_type, ObjectType)) {
|
||||
pytalloc_Object *ret
|
||||
= (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
|
||||
ret->talloc_ctx = talloc_new(NULL);
|
||||
if (ret->talloc_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
|
||||
ret->ptr = ptr;
|
||||
return (PyObject *)ret;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"pytalloc_reference_ex() called for object type "
|
||||
"not based on talloc");
|
||||
return NULL;
|
||||
}
|
||||
if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
|
||||
ret->ptr = ptr;
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
@ -121,6 +211,18 @@ _PUBLIC_ int pytalloc_Check(PyObject *obj)
|
||||
return PyObject_TypeCheck(obj, tp);
|
||||
}
|
||||
|
||||
_PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
|
||||
{
|
||||
PyTypeObject *tp = pytalloc_GetBaseObjectType();
|
||||
|
||||
return PyObject_TypeCheck(obj, tp);
|
||||
}
|
||||
|
||||
_PUBLIC_ size_t pytalloc_BaseObject_size(void)
|
||||
{
|
||||
return sizeof(pytalloc_BaseObject);
|
||||
}
|
||||
|
||||
_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
|
||||
{
|
||||
void *ptr = _pytalloc_get_ptr(py_obj);
|
||||
@ -138,10 +240,22 @@ _PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
|
||||
|
||||
_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
|
||||
{
|
||||
return ((pytalloc_Object *)py_obj)->ptr;
|
||||
if (pytalloc_BaseObject_check(py_obj)) {
|
||||
return ((pytalloc_BaseObject *)py_obj)->ptr;
|
||||
}
|
||||
if (pytalloc_Check(py_obj)) {
|
||||
return ((pytalloc_Object *)py_obj)->ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
|
||||
{
|
||||
return ((pytalloc_Object *)py_obj)->talloc_ctx;
|
||||
if (pytalloc_BaseObject_check(py_obj)) {
|
||||
return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
|
||||
}
|
||||
if (pytalloc_Check(py_obj)) {
|
||||
return ((pytalloc_Object *)py_obj)->talloc_ctx;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -42,6 +42,18 @@ static PyObject *testpytalloc_get_object_type(PyObject *mod) {
|
||||
return type;
|
||||
}
|
||||
|
||||
static PyObject *testpytalloc_base_new(PyTypeObject *mod)
|
||||
{
|
||||
char *obj = talloc_strdup(NULL, "This is a test string for a BaseObject");;
|
||||
return pytalloc_steal(pytalloc_GetBaseObjectType(), obj);
|
||||
}
|
||||
|
||||
static PyObject *testpytalloc_base_get_object_type(PyObject *mod) {
|
||||
PyObject *type = (PyObject *)pytalloc_GetBaseObjectType();
|
||||
Py_INCREF(type);
|
||||
return type;
|
||||
}
|
||||
|
||||
static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
|
||||
PyObject *source = NULL;
|
||||
void *ptr;
|
||||
@ -53,13 +65,30 @@ static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
|
||||
return pytalloc_reference_ex(pytalloc_GetObjectType(), ptr, ptr);
|
||||
}
|
||||
|
||||
static PyObject *testpytalloc_base_reference(PyObject *mod, PyObject *args) {
|
||||
PyObject *source = NULL;
|
||||
void *mem_ctx;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", pytalloc_GetBaseObjectType(), &source)) {
|
||||
return NULL;
|
||||
}
|
||||
mem_ctx = pytalloc_get_mem_ctx(source);
|
||||
return pytalloc_reference_ex(pytalloc_GetBaseObjectType(), mem_ctx, mem_ctx);
|
||||
}
|
||||
|
||||
static PyMethodDef test_talloc_methods[] = {
|
||||
{ "new", (PyCFunction)testpytalloc_new, METH_NOARGS,
|
||||
"create a talloc Object with a testing string"},
|
||||
{ "get_object_type", (PyCFunction)testpytalloc_get_object_type, METH_NOARGS,
|
||||
"call pytalloc_GetObjectType"},
|
||||
{ "base_new", (PyCFunction)testpytalloc_base_new, METH_NOARGS,
|
||||
"create a talloc BaseObject with a testing string"},
|
||||
{ "base_get_object_type", (PyCFunction)testpytalloc_base_get_object_type, METH_NOARGS,
|
||||
"call pytalloc_GetBaseObjectType"},
|
||||
{ "reference", (PyCFunction)testpytalloc_reference, METH_VARARGS,
|
||||
"call pytalloc_reference_ex"},
|
||||
{ "base_reference", (PyCFunction)testpytalloc_base_reference, METH_VARARGS,
|
||||
"call pytalloc_reference_ex"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -104,6 +133,46 @@ static PyTypeObject DObject_Type = {
|
||||
.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
|
||||
};
|
||||
|
||||
static PyTypeObject DBaseObject_Type;
|
||||
|
||||
static int d_base_object_destructor(void *ptr)
|
||||
{
|
||||
PyObject *destructor_func = *talloc_get_type(ptr, PyObject*);
|
||||
PyObject *ret;
|
||||
ret = PyObject_CallObject(destructor_func, NULL);
|
||||
Py_DECREF(destructor_func);
|
||||
if (ret == NULL) {
|
||||
PyErr_Print();
|
||||
} else {
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *d_base_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyObject *destructor_func = NULL;
|
||||
PyObject **obj;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &destructor_func))
|
||||
return NULL;
|
||||
Py_INCREF(destructor_func);
|
||||
|
||||
obj = talloc(NULL, PyObject*);
|
||||
*obj = destructor_func;
|
||||
|
||||
talloc_set_destructor((void*)obj, d_base_object_destructor);
|
||||
return pytalloc_steal(&DBaseObject_Type, obj);
|
||||
}
|
||||
|
||||
static PyTypeObject DBaseObject_Type = {
|
||||
.tp_name = "_test_pytalloc.DBaseObject",
|
||||
.tp_methods = NULL,
|
||||
.tp_new = d_base_object_new,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
|
||||
};
|
||||
|
||||
#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
@ -126,6 +195,12 @@ static PyObject *module_init(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBaseObject_Type.tp_basicsize = pytalloc_BaseObject_size();
|
||||
DBaseObject_Type.tp_base = pytalloc_GetBaseObjectType();
|
||||
if (PyType_Ready(&DBaseObject_Type) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
m = PyModule_Create(&moduledef);
|
||||
#else
|
||||
@ -140,6 +215,10 @@ static PyObject *module_init(void)
|
||||
Py_INCREF(DObject_Type.tp_base);
|
||||
PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
|
||||
|
||||
Py_INCREF(&DBaseObject_Type);
|
||||
Py_INCREF(DBaseObject_Type.tp_base);
|
||||
PyModule_AddObject(m, "DBaseObject", (PyObject *)&DBaseObject_Type);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,12 @@ class TallocTests(unittest.TestCase):
|
||||
self.assertTrue(repr(obj).startswith(prefix))
|
||||
self.assertEqual(repr(obj), str(obj))
|
||||
|
||||
def test_base_repr(self):
|
||||
obj = _test_pytalloc.base_new()
|
||||
prefix = '<talloc.BaseObject talloc based object at'
|
||||
self.assertTrue(repr(obj).startswith(prefix))
|
||||
self.assertEqual(repr(obj), str(obj))
|
||||
|
||||
def test_destructor(self):
|
||||
# Check correct lifetime of the talloc'd data
|
||||
lst = []
|
||||
@ -52,6 +58,15 @@ class TallocTests(unittest.TestCase):
|
||||
gc.collect()
|
||||
self.assertEqual(lst, ['dead'])
|
||||
|
||||
def test_base_destructor(self):
|
||||
# Check correct lifetime of the talloc'd data
|
||||
lst = []
|
||||
obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
|
||||
self.assertEqual(lst, [])
|
||||
del obj
|
||||
gc.collect()
|
||||
self.assertEqual(lst, ['dead'])
|
||||
|
||||
|
||||
class TallocComparisonTests(unittest.TestCase):
|
||||
|
||||
@ -94,13 +109,54 @@ class TallocComparisonTests(unittest.TestCase):
|
||||
self.assertFalse(obj1 >= obj2)
|
||||
self.assertFalse(obj1 > obj2)
|
||||
|
||||
class TallocBaseComparisonTests(unittest.TestCase):
|
||||
|
||||
def test_compare_same(self):
|
||||
obj1 = _test_pytalloc.base_new()
|
||||
self.assertTrue(obj1 == obj1)
|
||||
self.assertFalse(obj1 != obj1)
|
||||
self.assertTrue(obj1 <= obj1)
|
||||
self.assertFalse(obj1 < obj1)
|
||||
self.assertTrue(obj1 >= obj1)
|
||||
self.assertFalse(obj1 > obj1)
|
||||
|
||||
def test_compare_different(self):
|
||||
# object comparison is consistent
|
||||
obj1, obj2 = sorted([
|
||||
_test_pytalloc.base_new(),
|
||||
_test_pytalloc.base_new()])
|
||||
self.assertFalse(obj1 == obj2)
|
||||
self.assertTrue(obj1 != obj2)
|
||||
self.assertTrue(obj1 <= obj2)
|
||||
self.assertTrue(obj1 < obj2)
|
||||
self.assertFalse(obj1 >= obj2)
|
||||
self.assertFalse(obj1 > obj2)
|
||||
|
||||
def test_compare_different_types(self):
|
||||
# object comparison falls back to comparing types
|
||||
if sys.version_info >= (3, 0):
|
||||
# In Python 3, types are unorderable -- nothing to test
|
||||
return
|
||||
if talloc.BaseObject < _test_pytalloc.DBaseObject:
|
||||
obj1 = _test_pytalloc.base_new()
|
||||
obj2 = _test_pytalloc.DBaseObject(dummy_func)
|
||||
else:
|
||||
obj2 = _test_pytalloc.base_new()
|
||||
obj1 = _test_pytalloc.DBaseObject(dummy_func)
|
||||
self.assertFalse(obj1 == obj2)
|
||||
self.assertTrue(obj1 != obj2)
|
||||
self.assertTrue(obj1 <= obj2)
|
||||
self.assertTrue(obj1 < obj2)
|
||||
self.assertFalse(obj1 >= obj2)
|
||||
self.assertFalse(obj1 > obj2)
|
||||
|
||||
|
||||
class TallocUtilTests(unittest.TestCase):
|
||||
|
||||
def test_get_type(self):
|
||||
self.assertTrue(talloc.Object is _test_pytalloc.get_object_type())
|
||||
|
||||
def test_refrence(self):
|
||||
def test_reference(self):
|
||||
# Check correct lifetime of the talloc'd data with multiple references
|
||||
lst = []
|
||||
obj = _test_pytalloc.DObject(lambda: lst.append('dead'))
|
||||
@ -112,6 +168,21 @@ class TallocUtilTests(unittest.TestCase):
|
||||
gc.collect()
|
||||
self.assertEqual(lst, ['dead'])
|
||||
|
||||
def test_get_base_type(self):
|
||||
self.assertTrue(talloc.BaseObject is _test_pytalloc.base_get_object_type())
|
||||
|
||||
def test_base_reference(self):
|
||||
# Check correct lifetime of the talloc'd data with multiple references
|
||||
lst = []
|
||||
obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
|
||||
ref = _test_pytalloc.base_reference(obj)
|
||||
del obj
|
||||
gc.collect()
|
||||
self.assertEqual(lst, [])
|
||||
del ref
|
||||
gc.collect()
|
||||
self.assertEqual(lst, ['dead'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.TestProgram()
|
||||
|
Loading…
x
Reference in New Issue
Block a user