[pypy-svn] r74229 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include src test
afa at codespeak.net
afa at codespeak.net
Thu Apr 29 17:06:53 CEST 2010
Author: afa
Date: Thu Apr 29 17:06:52 2010
New Revision: 74229
Added:
pypy/branch/cpython-extension/pypy/module/cpyext/src/cobject.c (contents, props changed)
Removed:
pypy/branch/cpython-extension/pypy/module/cpyext/pycobject.py
Modified:
pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
pypy/branch/cpython-extension/pypy/module/cpyext/api.py
pypy/branch/cpython-extension/pypy/module/cpyext/include/pycobject.h
pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pycobject.py
Log:
Give up with the rpython-level CPyObject, the memory management was never correct.
Since it's used from C only, simply copy the C version.
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py Thu Apr 29 17:06:52 2010
@@ -59,7 +59,6 @@
import pypy.module.cpyext.mapping
import pypy.module.cpyext.iterator
import pypy.module.cpyext.unicodeobject
-import pypy.module.cpyext.pycobject
import pypy.module.cpyext.sysmodule
import pypy.module.cpyext.number
import pypy.module.cpyext.sliceobject
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py Thu Apr 29 17:06:52 2010
@@ -261,6 +261,10 @@
'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject',
'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', 'init_bufferobject',
+ 'PyCObject_FromVoidPtr', 'PyCObject_FromVoidPtrAndDesc', 'PyCObject_AsVoidPtr',
+ 'PyCObject_GetDesc', 'PyCObject_Import', 'PyCObject_SetVoidPtr',
+ 'PyCObject_Type', 'init_pycobject',
+
'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
]
TYPES = {}
@@ -476,8 +480,10 @@
def setup_init_functions(eci):
init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci)
+ init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci)
INIT_FUNCTIONS.extend([
lambda space: init_buffer(),
+ lambda space: init_pycobject(),
])
def init_function(func):
@@ -690,6 +696,7 @@
source_dir / "pythonrun.c",
source_dir / "bufferobject.c",
source_dir / "object.c",
+ source_dir / "cobject.c",
],
separate_module_sources = [code],
export_symbols=export_symbols_eci,
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/pycobject.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/pycobject.h (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pycobject.h Thu Apr 29 17:06:52 2010
@@ -4,6 +4,41 @@
extern "C" {
#endif
+PyAPI_DATA(PyTypeObject) PyCObject_Type;
+
+#define PyCObject_Check(op) (op->ob_type == &PyCObject_Type)
+
+/* Create a PyCObject from a pointer to a C object and an optional
+ destructor function. If the second argument is non-null, then it
+ will be called with the first argument if and when the PyCObject is
+ destroyed.
+
+*/
+PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtr(
+ void *cobj, void (*destruct)(void*));
+
+
+/* Create a PyCObject from a pointer to a C object, a description object,
+ and an optional destructor function. If the third argument is non-null,
+ then it will be called with the first and second arguments if and when
+ the PyCObject is destroyed.
+*/
+PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtrAndDesc(
+ void *cobj, void *desc, void (*destruct)(void*,void*));
+
+/* Retrieve a pointer to a C object from a PyCObject. */
+PyAPI_FUNC(void *) PyCObject_AsVoidPtr(PyObject *);
+
+/* Retrieve a pointer to a description object from a PyCObject. */
+PyAPI_FUNC(void *) PyCObject_GetDesc(PyObject *);
+
+/* Import a pointer to a C object from a module using a PyCObject. */
+PyAPI_FUNC(void *) PyCObject_Import(char *module_name, char *cobject_name);
+
+/* Modify a C object. Fails (==0) if object has a destructor. */
+PyAPI_FUNC(int) PyCObject_SetVoidPtr(PyObject *self, void *cobj);
+
+
#if (PY_VERSION_HEX >= 0x02060000 || defined(Py_BUILD_CORE))
typedef struct {
PyObject_HEAD
Added: pypy/branch/cpython-extension/pypy/module/cpyext/src/cobject.c
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/src/cobject.c Thu Apr 29 17:06:52 2010
@@ -0,0 +1,158 @@
+
+/* Wrap void* pointers to be passed between C modules */
+
+#include "Python.h"
+
+
+/* Declarations for objects of type PyCObject */
+
+typedef void (*destructor1)(void *);
+typedef void (*destructor2)(void *, void*);
+
+PyObject *
+PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *))
+{
+ PyCObject *self;
+
+ self = PyObject_NEW(PyCObject, &PyCObject_Type);
+ if (self == NULL)
+ return NULL;
+ self->cobject=cobj;
+ self->destructor=destr;
+ self->desc=NULL;
+
+ return (PyObject *)self;
+}
+
+PyObject *
+PyCObject_FromVoidPtrAndDesc(void *cobj, void *desc,
+ void (*destr)(void *, void *))
+{
+ PyCObject *self;
+
+ if (!desc) {
+ PyErr_SetString(PyExc_TypeError,
+ "PyCObject_FromVoidPtrAndDesc called with null"
+ " description");
+ return NULL;
+ }
+ self = PyObject_NEW(PyCObject, &PyCObject_Type);
+ if (self == NULL)
+ return NULL;
+ self->cobject = cobj;
+ self->destructor = (destructor1)destr;
+ self->desc = desc;
+
+ return (PyObject *)self;
+}
+
+void *
+PyCObject_AsVoidPtr(PyObject *self)
+{
+ if (self) {
+ if (self->ob_type == &PyCObject_Type)
+ return ((PyCObject *)self)->cobject;
+ PyErr_SetString(PyExc_TypeError,
+ "PyCObject_AsVoidPtr with non-C-object");
+ }
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "PyCObject_AsVoidPtr called with null pointer");
+ return NULL;
+}
+
+void *
+PyCObject_GetDesc(PyObject *self)
+{
+ if (self) {
+ if (self->ob_type == &PyCObject_Type)
+ return ((PyCObject *)self)->desc;
+ PyErr_SetString(PyExc_TypeError,
+ "PyCObject_GetDesc with non-C-object");
+ }
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "PyCObject_GetDesc called with null pointer");
+ return NULL;
+}
+
+void *
+PyCObject_Import(char *module_name, char *name)
+{
+ PyObject *m, *c;
+ void *r = NULL;
+
+ if ((m = PyImport_ImportModule(module_name))) {
+ if ((c = PyObject_GetAttrString(m,name))) {
+ r = PyCObject_AsVoidPtr(c);
+ Py_DECREF(c);
+ }
+ Py_DECREF(m);
+ }
+ return r;
+}
+
+int
+PyCObject_SetVoidPtr(PyObject *self, void *cobj)
+{
+ PyCObject* cself = (PyCObject*)self;
+ if (cself == NULL || !PyCObject_Check(cself) ||
+ cself->destructor != NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid call to PyCObject_SetVoidPtr");
+ return 0;
+ }
+ cself->cobject = cobj;
+ return 1;
+}
+
+static void
+PyCObject_dealloc(PyCObject *self)
+{
+ if (self->destructor) {
+ if(self->desc)
+ ((destructor2)(self->destructor))(self->cobject, self->desc);
+ else
+ (self->destructor)(self->cobject);
+ }
+ PyObject_DEL(self);
+}
+
+
+PyDoc_STRVAR(PyCObject_Type__doc__,
+"C objects to be exported from one extension module to another\n\
+\n\
+C objects are used for communication between extension modules. They\n\
+provide a way for an extension module to export a C interface to other\n\
+extension modules, so that extension modules can use the Python import\n\
+mechanism to link to one another.");
+
+PyTypeObject PyCObject_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "PyCObject", /*tp_name*/
+ sizeof(PyCObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)PyCObject_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ 0, /*tp_flags*/
+ PyCObject_Type__doc__ /*tp_doc*/
+};
+
+void init_pycobject()
+{
+ PyType_Ready(&PyCObject_Type);
+}
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pycobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pycobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pycobject.py Thu Apr 29 17:06:52 2010
@@ -1,32 +1,29 @@
-import py
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.test.test_api import BaseApiTest
-from pypy.module.cpyext.pycobject import destructor_short, PyCObject
-
-class TestPyCObject(BaseApiTest):
- def test_pycobject(self, space, api):
- ptr = rffi.cast(rffi.VOIDP_real, 1234)
- obj = api.PyCObject_FromVoidPtr(ptr, lltype.nullptr(destructor_short.TO))
- assert api.PyCObject_Check(obj)
- assert api.PyCObject_AsVoidPtr(obj) == ptr
- assert rffi.cast(PyCObject, obj).c_cobject == ptr
- api.Py_DecRef(obj)
-
- obj = api.PyCObject_FromVoidPtrAndDesc(ptr, ptr,
- lltype.nullptr(destructor_short.TO))
- api.Py_DecRef(obj)
-
- def test_pycobject_import(self, space, api):
- ptr = rffi.cast(rffi.VOIDP_real, 1234)
- obj = api.PyCObject_FromVoidPtr(ptr, lltype.nullptr(destructor_short.TO))
- space.setattr(space.sys, space.wrap("_cpyext_cobject"), obj)
-
- charp1 = rffi.str2charp("sys")
- charp2 = rffi.str2charp("_cpyext_cobject")
- assert api.PyCObject_Import(charp1, charp2) == ptr
- rffi.free_charp(charp1)
- rffi.free_charp(charp2)
-
- api.Py_DecRef(obj)
- space.delattr(space.sys, space.wrap("_cpyext_cobject"))
+class AppTestStringObject(AppTestCpythonExtensionBase):
+ def test_pycobject_import(self):
+ module = self.import_extension('foo', [
+ ("set_ptr", "METH_O",
+ """
+ PyObject *pointer, *module;
+ void *ptr = PyLong_AsVoidPtr(args);
+ if (PyErr_Occurred()) return NULL;
+ pointer = PyCObject_FromVoidPtr(ptr, NULL);
+ if (PyErr_Occurred()) return NULL;
+ module = PyImport_ImportModule("foo");
+ PyModule_AddObject(module, "_ptr", pointer);
+ Py_DECREF(module);
+ if (PyErr_Occurred()) return NULL;
+ Py_RETURN_NONE;
+ """),
+ ("get_ptr", "METH_NOARGS",
+ """
+ void *ptr = PyCObject_Import("foo", "_ptr");
+ if (PyErr_Occurred()) return NULL;
+ return PyLong_FromVoidPtr(ptr);
+ """)])
+ module.set_ptr(1234)
+ assert "PyCObject object" in str(module._ptr)
+ import gc; gc.collect()
+ assert module.get_ptr() == 1234
+ del module._ptr
More information about the Pypy-commit
mailing list