Backported PyCapsule from 3.1, and converted most uses of

CObject to PyCapsule.
This commit is contained in:
Larry Hastings 2010-03-25 00:54:54 +00:00
parent 53ff86ea5f
commit 402b73fb8d
40 changed files with 1048 additions and 127 deletions

150
Doc/c-api/capsule.rst Normal file
View File

@ -0,0 +1,150 @@
.. highlightlang:: c
.. _capsules:
Capsules
--------
.. index:: object: Capsule
Refer to :ref:`using-capsules` for more information on using these objects.
.. ctype:: PyCapsule
This subtype of :ctype:`PyObject` represents an opaque value, useful for C
extension modules who need to pass an opaque value (as a :ctype:`void\*`
pointer) through Python code to other C code. It is often used to make a C
function pointer defined in one module available to other modules, so the
regular import mechanism can be used to access C APIs defined in dynamically
loaded modules.
.. ctype:: PyCapsule_Destructor
The type of a destructor callback for a capsule. Defined as::
typedef void (*PyCapsule_Destructor)(PyObject *);
See :cfunc:`PyCapsule_New` for the semantics of PyCapsule_Destructor
callbacks.
.. cfunction:: int PyCapsule_CheckExact(PyObject *p)
Return true if its argument is a :ctype:`PyCapsule`.
.. cfunction:: PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
Create a :ctype:`PyCapsule` encapsulating the *pointer*. The *pointer*
argument may not be *NULL*.
On failure, set an exception and return *NULL*.
The *name* string may either be *NULL* or a pointer to a valid C string. If
non-*NULL*, this string must outlive the capsule. (Though it is permitted to
free it inside the *destructor*.)
If the *destructor* argument is not *NULL*, it will be called with the
capsule as its argument when it is destroyed.
If this capsule will be stored as an attribute of a module, the *name* should
be specified as ``modulename.attributename``. This will enable other modules
to import the capsule using :cfunc:`PyCapsule_Import`.
.. cfunction:: void* PyCapsule_GetPointer(PyObject *capsule, const char *name)
Retrieve the *pointer* stored in the capsule. On failure, set an exception
and return *NULL*.
The *name* parameter must compare exactly to the name stored in the capsule.
If the name stored in the capsule is *NULL*, the *name* passed in must also
be *NULL*. Python uses the C function :cfunc:`strcmp` to compare capsule
names.
.. cfunction:: PyCapsule_Destructor PyCapsule_GetDestructor(PyObject *capsule)
Return the current destructor stored in the capsule. On failure, set an
exception and return *NULL*.
It is legal for a capsule to have a *NULL* destructor. This makes a *NULL*
return code somewhat ambiguous; use :cfunc:`PyCapsule_IsValid` or
:cfunc:`PyErr_Occurred` to disambiguate.
.. cfunction:: void* PyCapsule_GetContext(PyObject *capsule)
Return the current context stored in the capsule. On failure, set an
exception and return *NULL*.
It is legal for a capsule to have a *NULL* context. This makes a *NULL*
return code somewhat ambiguous; use :cfunc:`PyCapsule_IsValid` or
:cfunc:`PyErr_Occurred` to disambiguate.
.. cfunction:: const char* PyCapsule_GetName(PyObject *capsule)
Return the current name stored in the capsule. On failure, set an exception
and return *NULL*.
It is legal for a capsule to have a *NULL* name. This makes a *NULL* return
code somewhat ambiguous; use :cfunc:`PyCapsule_IsValid` or
:cfunc:`PyErr_Occurred` to disambiguate.
.. cfunction:: void* PyCapsule_Import(const char *name, int no_block)
Import a pointer to a C object from a capsule attribute in a module. The
*name* parameter should specify the full name to the attribute, as in
``module.attribute``. The *name* stored in the capsule must match this
string exactly. If *no_block* is true, import the module without blocking
(using :cfunc:`PyImport_ImportModuleNoBlock`). If *no_block* is false,
import the module conventionally (using :cfunc:`PyImport_ImportModule`).
Return the capsule's internal *pointer* on success. On failure, set an
exception and return *NULL*. However, if :cfunc:`PyCapsule_Import` failed to
import the module, and *no_block* was true, no exception is set.
.. cfunction:: int PyCapsule_IsValid(PyObject *capsule, const char *name)
Determines whether or not *capsule* is a valid capsule. A valid capsule is
non-*NULL*, passes :cfunc:`PyCapsule_CheckExact`, has a non-*NULL* pointer
stored in it, and its internal name matches the *name* parameter. (See
:cfunc:`PyCapsule_GetPointer` for information on how capsule names are
compared.)
In other words, if :cfunc:`PyCapsule_IsValid` returns a true value, calls to
any of the accessors (any function starting with :cfunc:`PyCapsule_Get`) are
guaranteed to succeed.
Return a nonzero value if the object is valid and matches the name passed in.
Return 0 otherwise. This function will not fail.
.. cfunction:: int PyCapsule_SetContext(PyObject *capsule, void *context)
Set the context pointer inside *capsule* to *context*.
Return 0 on success. Return nonzero and set an exception on failure.
.. cfunction:: int PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor)
Set the destructor inside *capsule* to *destructor*.
Return 0 on success. Return nonzero and set an exception on failure.
.. cfunction:: int PyCapsule_SetName(PyObject *capsule, const char *name)
Set the name inside *capsule* to *name*. If non-*NULL*, the name must
outlive the capsule. If the previous *name* stored in the capsule was not
*NULL*, no attempt is made to free it.
Return 0 on success. Return nonzero and set an exception on failure.
.. cfunction:: int PyCapsule_SetPointer(PyObject *capsule, void *pointer)
Set the void pointer inside *capsule* to *pointer*. The pointer may not be
*NULL*.
Return 0 on success. Return nonzero and set an exception on failure.

View File

@ -7,8 +7,11 @@ CObjects
.. index:: object: CObject
Refer to :ref:`using-cobjects` for more information on using these objects.
.. warning::
The CObject API is deprecated as of Python 2.7. Please switch to the new
:ref:`capsules` API.
.. ctype:: PyCObject

View File

@ -100,6 +100,7 @@ Other Objects
descriptor.rst
slice.rst
weakref.rst
capsule.rst
cobject.rst
cell.rst
gen.rst

View File

@ -55,6 +55,45 @@ PyBuffer_FromReadWriteMemory:int:size::
PyBuffer_New:PyObject*::+1:
PyBuffer_New:int:size::
PyCapsule_GetContext:void *:::
PyCapsule_GetContext:PyObject*:self:0:
PyCapsule_GetDestructor:void (*)(PyObject *):::
PyCapsule_GetDestructor:PyObject*:self:0:
PyCapsule_GetName:const char *:::
PyCapsule_GetName:PyObject*:self:0:
PyCapsule_GetPointer:void*:::
PyCapsule_GetPointer:PyObject*:self:0:
PyCapsule_GetPointer:const char *:name::
PyCapsule_Import:void *:::
PyCapsule_Import:const char *:name::
PyCapsule_Import:int:no_block::
PyCapsule_New:PyObject*::+1:
PyCapsule_New:void*:pointer::
PyCapsule_New:const char *:name::
PyCapsule_New::void (* destructor)(PyObject* )::
PyCapsule_SetContext:int:::
PyCapsule_SetContext:PyObject*:self:0:
PyCapsule_SetContext:void *:context::
PyCapsule_SetDestructor:int:::
PyCapsule_SetDestructor:PyObject*:self:0:
PyCapsule_SetDestructor:void (*)(PyObject *):destructor::
PyCapsule_SetName:int:::
PyCapsule_SetName:PyObject*:self:0:
PyCapsule_SetName:const char *:name::
PyCapsule_SetPointer:int:::
PyCapsule_SetPointer:PyObject*:self:0:
PyCapsule_SetPointer:void*:pointer::
PyCObject_AsVoidPtr:void*:::
PyCObject_AsVoidPtr:PyObject*:self:0:

View File

@ -1060,7 +1060,7 @@ already if the symbol ``__cplusplus`` is defined (all recent C++ compilers
define this symbol).
.. _using-cobjects:
.. _using-capsules:
Providing a C API for an Extension Module
=========================================
@ -1096,23 +1096,40 @@ avoid name clashes with other extension modules (as discussed in section
other extension modules must be exported in a different way.
Python provides a special mechanism to pass C-level information (pointers) from
one extension module to another one: CObjects. A CObject is a Python data type
which stores a pointer (:ctype:`void \*`). CObjects can only be created and
one extension module to another one: Capsules. A Capsule is a Python data type
which stores a pointer (:ctype:`void \*`). Capsules can only be created and
accessed via their C API, but they can be passed around like any other Python
object. In particular, they can be assigned to a name in an extension module's
namespace. Other extension modules can then import this module, retrieve the
value of this name, and then retrieve the pointer from the CObject.
value of this name, and then retrieve the pointer from the Capsule.
There are many ways in which CObjects can be used to export the C API of an
extension module. Each name could get its own CObject, or all C API pointers
could be stored in an array whose address is published in a CObject. And the
There are many ways in which Capsules can be used to export the C API of an
extension module. Each function could get its own Capsule, or all C API pointers
could be stored in an array whose address is published in a Capsule. And the
various tasks of storing and retrieving the pointers can be distributed in
different ways between the module providing the code and the client modules.
Whichever method you choose, it's important to name your Capsules properly.
The function :cfunc:`PyCapsule_New` takes a name parameter
(:ctype:`const char \*`); you're permitted to pass in a *NULL* name, but
we strongly encourage you to specify a name. Properly named Capsules provide
a degree of runtime type-safety; there is no feasible way to tell one unnamed
Capsule from another.
In particular, Capsules used to expose C APIs should be given a name following
this convention::
modulename.attributename
The convenience function :cfunc:`PyCapsule_Import` makes it easy to
load a C API provided via a Capsule, but only if the Capsule's name
matches this convention. This behavior gives C API users a high degree
of certainty that the Capsule they load contains the correct C API.
The following example demonstrates an approach that puts most of the burden on
the writer of the exporting module, which is appropriate for commonly used
library modules. It stores all C API pointers (just one in the example!) in an
array of :ctype:`void` pointers which becomes the value of a CObject. The header
array of :ctype:`void` pointers which becomes the value of a Capsule. The header
file corresponding to the module provides a macro that takes care of importing
the module and retrieving its C API pointers; client modules only have to call
this macro before accessing the C API.
@ -1174,8 +1191,8 @@ function must take care of initializing the C API pointer array::
/* Initialize the C API pointer array */
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
/* Create a CObject containing the API pointer array's address */
c_api_object = PyCObject_FromVoidPtr((void *)PySpam_API, NULL);
/* Create a Capsule containing the API pointer array's address */
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);
if (c_api_object != NULL)
PyModule_AddObject(m, "_C_API", c_api_object);
@ -1217,28 +1234,14 @@ like this::
#define PySpam_System \
(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
/* Return -1 and set exception on error, 0 on success. */
/* Return -1 on error, 0 on success.
* PyCapsule_Import will set an exception if there's an error.
*/
static int
import_spam(void)
{
PyObject *c_api_object;
PyObject *module;
module = PyImport_ImportModule("spam");
if (module == NULL)
return -1;
c_api_object = PyObject_GetAttrString(module, "_C_API");
if (c_api_object == NULL) {
Py_DECREF(module);
return -1;
}
if (PyCObject_Check(c_api_object))
PySpam_API = (void **)PyCObject_AsVoidPtr(c_api_object);
Py_DECREF(c_api_object);
Py_DECREF(module);
return 0;
PySpam_API = (void **)PyCapsule_Import("spam._C_API", 0);
return (PySpam_API != NULL) ? 0 : -1;
}
#endif
@ -1270,11 +1273,11 @@ The main disadvantage of this approach is that the file :file:`spammodule.h` is
rather complicated. However, the basic structure is the same for each function
that is exported, so it has to be learned only once.
Finally it should be mentioned that CObjects offer additional functionality,
Finally it should be mentioned that Capsules offer additional functionality,
which is especially useful for memory allocation and deallocation of the pointer
stored in a CObject. The details are described in the Python/C API Reference
Manual in the section :ref:`cobjects` and in the implementation of CObjects (files
:file:`Include/cobject.h` and :file:`Objects/cobject.c` in the Python source
stored in a Capsule. The details are described in the Python/C API Reference
Manual in the section :ref:`capsules` and in the implementation of Capsules (files
:file:`Include/pycapsule.h` and :file:`Objects/pycapsule.c` in the Python source
code distribution).
.. rubric:: Footnotes

View File

@ -107,6 +107,7 @@
#include "classobject.h"
#include "fileobject.h"
#include "cobject.h"
#include "pycapsule.h"
#include "traceback.h"
#include "sliceobject.h"
#include "cellobject.h"

View File

@ -18,9 +18,12 @@ extern "C" {
This would typically be done in your init function.
*/
#define PycStringIO_CAPSULE_NAME "cStringIO.cStringIO_CAPI"
#define PycString_IMPORT \
PycStringIO = (struct PycStringIO_CAPI*)PyCObject_Import("cStringIO", \
"cStringIO_CAPI")
PycStringIO = ((struct PycStringIO_CAPI*)PyCapsule_Import(\
PycStringIO_CAPSULE_NAME, 0))
/* Basic functions to manipulate cStringIO objects from C */

View File

@ -6,6 +6,8 @@
to other extension modules, so that extension modules can use the
Python import mechanism to link to one another.
DEPRECATED - Use PyCapsule objects instead.
CObject will be removed in 2.8 (if there is one).
*/
#ifndef Py_COBJECT_H

View File

@ -158,6 +158,8 @@ typedef struct {
} PyDateTime_CAPI;
#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI"
/* "magic" constant used to partially protect against developer mistakes. */
#define DATETIME_API_MAGIC 0x414548d5
@ -186,15 +188,7 @@ typedef struct {
static PyDateTime_CAPI *PyDateTimeAPI = NULL;
#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_Import("datetime", \
"datetime_CAPI")
/* This macro would be used if PyCObject_ImportEx() was created.
#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_ImportEx("datetime", \
"datetime_CAPI", \
DATETIME_API_MAGIC)
*/
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
/* Macros for type checking when not building the Python core. */
#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType)

View File

@ -80,6 +80,9 @@ typedef struct {
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)
#define PyCurses_CAPSULE_NAME "_curses._C_API"
#ifdef CURSES_MODULE
/* This section is used when compiling _cursesmodule.c */
@ -94,16 +97,8 @@ static void **PyCurses_API;
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}
#define import_curses() \
{ \
PyObject *module = PyImport_ImportModuleNoBlock("_curses"); \
if (module != NULL) { \
PyObject *module_dict = PyModule_GetDict(module); \
PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \
if (PyCObject_Check(c_api_object)) { \
PyCurses_API = (void **)PyCObject_AsVoidPtr(c_api_object); \
} \
} \
}
PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1);
#endif
/* general error messages */

148
Include/pycapsule.h Normal file
View File

@ -0,0 +1,148 @@
/* Capsule objects let you wrap a C "void *" pointer in a Python
object. They're a way of passing data through the Python interpreter
without creating your own custom type.
Capsules are used for communication between extension modules.
They provide a way for an extension module to export a C interface
to other extension modules, so that extension modules can use the
Python import mechanism to link to one another.
For more information, please see "c-api/capsule.html" in the
documentation.
*/
#ifndef Py_CAPSULE_H
#define Py_CAPSULE_H
#ifdef __cplusplus
extern "C" {
#endif
PyAPI_DATA(PyTypeObject) PyCapsule_Type;
typedef void (*PyCapsule_Destructor)(PyObject *);
#define PyCapsule_CheckExact(op) (Py_TYPE(op) == &PyCapsule_Type)
PyAPI_FUNC(PyObject *) PyCapsule_New(
void *pointer,
const char *name,
PyCapsule_Destructor destructor);
PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *capsule, const char *name);
PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *capsule);
PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *capsule);
PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *capsule);
PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *capsule, const char *name);
PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *capsule, void *pointer);
PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor);
PyAPI_FUNC(int) PyCapsule_SetName(PyObject *capsule, const char *name);
PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *capsule, void *context);
PyAPI_FUNC(void *) PyCapsule_Import(const char *name, int no_block);
#define PYTHON_USING_CAPSULE
#define PYCAPSULE_INSTANTIATE_DESTRUCTOR(name, destructor) \
static void pycapsule_destructor_ ## name(PyObject *ptr) \
{ \
void *p = PyCapsule_GetPointer(ptr, name); \
if (p) { \
destructor(p); \
} \
} \
#define PYCAPSULE_NEW(pointer, name) \
(PyCapsule_New(pointer, name, capsule_destructor_ ## name))
#define PYCAPSULE_ISVALID(capsule, name) \
(PyCapsule_IsValid(capsule, name))
#define PYCAPSULE_DEREFERENCE(capsule, name) \
(PyCapsule_GetPointer(capsule, name))
#define PYCAPSULE_SET(capsule, name, value) \
(PyCapsule_IsValid(capsule, name) && PyCapsule_SetPointer(capsule, value))
/* module and attribute should be specified as string constants */
#define PYCAPSULE_IMPORT(module, attribute) \
(PyCapsule_Import(module "." attribute, 0))
/* begin public-domain code */
/*
** This code was written by Larry Hastings,
** and is dedicated to the public domain.
** It's designed to make it easy to switch
** from CObject to Capsule objects without losing
** backwards compatibility with prior versions
** of CPython. You're encouraged to copy this code
** (including this documentation) into your
** Python C extension.
**
** To use:
** * #define a name for the pointer you store in
** the CObject. If you make the CObject available
** as part of your module's API, this name should
** be "modulename.attributename", and it should be
** considered part of your API (so put it in your
** header file).
** * Specify a PYCAPSULE_INSTANTIATE_DESTRUCTOR(), in
** every C file that creates these CObjects. This
** is where you specify your object's destructor.
** * Change all calls to CObject_FromVoidPtr()
** and CObject_FromVoidPointerAndDesc() into
** PYCAPSULE_NEW() calls.
** * Change all calls to PyCObject_AsVoidPtr()
** into PYCAPSULE_DEREFERENCE() calls.
** * Change all calls to PyCObject_SetVoidPtr()
** into PYCAPSULE_SET() calls.
** * Change all calls to PyCObject_Import()
** into PYCAPSULE_IMPORT() calls. Note that
** the two arguments to PYCAPSULE_IMPORT()
** should both be string constants; that is,
** you should call
** PYCAPSULE_IMPORT("modulename", "attributename"),
** not PYCAPSULE_IMPORT(charstar1, charstar2).
*/
#ifndef PYTHON_USING_CAPSULE
#define PYCAPSULE_INSTANTIATE_DESTRUCTOR(name, destructor) \
static void pycapsule_destructor_ ## name(void *ptr) \
{ \
destructor(p); \
} \
#define PYCAPSULE_NEW(pointer, name) \
(PyCObject_FromVoidPtr(pointer, pycapsule_destructor_ ## name))
#define PYCAPSULE_ISVALID(capsule, name) \
(PyCObject_Check(capsule))
#define PYCAPSULE_DEREFERENCE(capsule, name) \
(PyCObject_AsVoidPtr(capsule))
#define PYCAPSULE_SET(capsule, name, value) \
(PyCObject_SetVoidPtr(capsule, value))
/* module and attribute should be specified as string constants */
#define PYCAPSULE_IMPORT(module, attribute) \
(PyCObject_Import(module, attribute))
#endif /* PYTHON_USING_CAPSULE */
/* end public-domain code */
#ifdef __cplusplus
}
#endif
#endif /* !Py_CAPSULE_H */

View File

@ -4,6 +4,7 @@
/* note: you must import expat.h before importing this module! */
#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0"
#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI"
struct PyExpat_CAPI
{

View File

@ -6,7 +6,9 @@
extern "C" {
#endif
/* revised ucnhash CAPI interface (exported through a PyCObject) */
/* revised ucnhash CAPI interface (exported through a "wrapper") */
#define PyUnicodeData_CAPSULE_NAME "unicodedata.ucnhash_CAPI"
typedef struct {

View File

@ -670,6 +670,7 @@ class SizeofTest(unittest.TestCase):
x = property(getx, setx, delx, "")
check(x, size(h + '4Pi'))
# PyCObject
# PyCapsule
# XXX
# rangeiterator
check(iter(xrange(1)), size(h + '4l'))

View File

@ -309,6 +309,7 @@ OBJECT_OBJS= \
Objects/bufferobject.o \
Objects/bytes_methods.o \
Objects/bytearrayobject.o \
Objects/capsule.o \
Objects/cellobject.o \
Objects/classobject.o \
Objects/cobject.o \
@ -642,6 +643,7 @@ PYTHON_HEADERS= \
Include/pgen.h \
Include/pgenheaders.h \
Include/pyarena.h \
Include/pycapsule.h \
Include/pyctype.h \
Include/pydebug.h \
Include/pyerrors.h \

View File

@ -138,6 +138,12 @@ Build
- Issue #7705: Fix linking on FreeBSD.
C-API
-----
- Issue #7992: A replacement PyCObject API, PyCapsule, has been backported
from Python 3.1.
Tests
-----

View File

@ -83,6 +83,13 @@
#define DONT_USE_SEH
#endif
#define CTYPES_CAPSULE_ERROROBJ "_ctypes/callproc.c error object"
CTYPES_CAPSULE_INSTANTIATE_DESTRUCTOR(CTYPES_CAPSULE_ERROROBJ)
#define CTYPES_CAPSULE_WCHAR_T "_ctypes/callproc.c wchar_t buffer from unicode"
CTYPES_CAPSULE_INSTANTIATE_DESTRUCTOR(CTYPES_CAPSULE_WCHAR_T)
/*
ctypes maintains thread-local storage that has space for two error numbers:
private copies of the system 'errno' value and, on Windows, the system error code
@ -134,14 +141,22 @@ _ctypes_get_errobj(int **pspace)
return NULL;
}
errobj = PyDict_GetItem(dict, error_object_name);
if (errobj)
if (errobj) {
#ifdef CTYPES_USING_CAPSULE
if (!PyCapsule_IsValid(errobj, CTYPES_CAPSULE_ERROROBJ)) {
PyErr_SetString(PyExc_RuntimeError,
"ctypes.error_object is an invalid capsule");
return NULL;
}
#endif /* CTYPES_USING_CAPSULE */
Py_INCREF(errobj);
}
else {
void *space = PyMem_Malloc(sizeof(int) * 2);
if (space == NULL)
return NULL;
memset(space, 0, sizeof(int) * 2);
errobj = PyCObject_FromVoidPtr(space, PyMem_Free);
errobj = CAPSULE_NEW(space, CTYPES_CAPSULE_ERROROBJ);
if (errobj == NULL)
return NULL;
if (-1 == PyDict_SetItem(dict, error_object_name,
@ -150,7 +165,7 @@ _ctypes_get_errobj(int **pspace)
return NULL;
}
}
*pspace = (int *)PyCObject_AsVoidPtr(errobj);
*pspace = (int *)CAPSULE_DEREFERENCE(errobj, CTYPES_CAPSULE_ERROROBJ);
return errobj;
}
@ -670,7 +685,7 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
return -1;
}
memset(pa->value.p, 0, size);
pa->keep = PyCObject_FromVoidPtr(pa->value.p, PyMem_Free);
pa->keep = CAPSULE_NEW(pa->value.p, CTYPES_CAPSULE_WCHAR_T);
if (!pa->keep) {
PyMem_Free(pa->value.p);
return -1;

View File

@ -10,6 +10,11 @@
#endif
#include "ctypes.h"
#define CTYPES_CAPSULE_WCHAR_T "_ctypes/cfield.c wchar_t buffer from unicode"
CTYPES_CAPSULE_INSTANTIATE_DESTRUCTOR(CTYPES_CAPSULE_WCHAR_T)
/******************************************************************/
/*
PyCField_Type
@ -1457,7 +1462,7 @@ Z_set(void *ptr, PyObject *value, Py_ssize_t size)
return PyErr_NoMemory();
}
memset(buffer, 0, size);
keep = PyCObject_FromVoidPtr(buffer, PyMem_Free);
keep = CAPSULE_NEW(buffer, CTYPES_CAPSULE_WCHAR_T);
if (!keep) {
Py_DECREF(value);
PyMem_Free(buffer);

View File

@ -445,6 +445,40 @@ PyObject *_ctypes_get_errobj(int **pspace);
extern PyObject *ComError;
#endif
#if PY_VERSION_HEX >= 0x020700A4
/* Use PyCapsule for 2.7 */
#define CTYPES_USING_CAPSULE
#define CTYPES_CAPSULE_INSTANTIATE_DESTRUCTOR(name) \
static void capsule_destructor_ ## name(PyObject *ptr) \
{ \
void *p = PyCapsule_GetPointer(ptr, name); \
if (p) { \
PyMem_Free(p); \
} \
} \
#define CAPSULE_NEW(pointer, name) \
(PyCapsule_New(pointer, name, capsule_destructor_ ## name))
#define CAPSULE_DEREFERENCE(capsule, name) \
(PyCapsule_GetPointer(capsule, name))
#else /* PY_VERSION_HEX >= 0x020700A4 */
/* Use CObject for 2.6 and before */
#define CTYPES_CAPSULE_INSTANTIATE_DESTRUCTOR(name)
#define CAPSULE_NEW(pointer, name) \
(PyCObject_FromVoidPtr(pointer, PyMem_Free))
#define CAPSULE_DEREFERENCE(capsule, name) \
(PyCObject_AsVoidPtr(capsule))
#endif /* PY_VERSION_HEX >= 0x020700A4 */
/*
Local Variables:
compile-command: "python setup.py -q build install --home ~"

View File

@ -172,7 +172,7 @@ static int initialisedcolors = FALSE;
/*
* Check the return code from a curses function and return None
* or raise an exception as appropriate. These are exported using the
* CObject API.
* capsule API.
*/
static PyObject *
@ -2745,8 +2745,8 @@ init_curses(void)
return;
ModDict = d; /* For PyCurses_InitScr to use later */
/* Add a CObject for the C API */
c_api_object = PyCObject_FromVoidPtr((void *)PyCurses_API, NULL);
/* Add a capsule for the C API */
c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME, NULL);
PyDict_SetItemString(d, "_C_API", c_api_object);
Py_DECREF(c_api_object);

View File

@ -3059,7 +3059,7 @@ init_elementtree(void)
#if defined(USE_PYEXPAT_CAPI)
/* link against pyexpat, if possible */
expat_capi = PyCObject_Import("pyexpat", "expat_CAPI");
expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
if (expat_capi) {
/* check that it's usable */
if (strcmp(expat_capi->magic, PyExpat_CAPI_MAGIC) != 0 ||

View File

@ -1428,6 +1428,157 @@ test_string_from_format(PyObject *self, PyObject *args)
#undef CHECK_1_FORMAT
}
/* Coverage testing of capsule objects. */
static const char *capsule_name = "capsule name";
static char *capsule_pointer = "capsule pointer";
static char *capsule_context = "capsule context";
static const char *capsule_error = NULL;
static int
capsule_destructor_call_count = 0;
static void
capsule_destructor(PyObject *o) {
capsule_destructor_call_count++;
if (PyCapsule_GetContext(o) != capsule_context) {
capsule_error = "context did not match in destructor!";
} else if (PyCapsule_GetDestructor(o) != capsule_destructor) {
capsule_error = "destructor did not match in destructor! (woah!)";
} else if (PyCapsule_GetName(o) != capsule_name) {
capsule_error = "name did not match in destructor!";
} else if (PyCapsule_GetPointer(o, capsule_name) != capsule_pointer) {
capsule_error = "pointer did not match in destructor!";
}
}
typedef struct {
char *name;
char *module;
char *attribute;
} known_capsule;
static PyObject *
test_capsule(PyObject *self, PyObject *args)
{
PyObject *object;
const char *error = NULL;
void *pointer;
void *pointer2;
known_capsule known_capsules[] = {
#define KNOWN_CAPSULE(module, name) { module "." name, module, name }
KNOWN_CAPSULE("_socket", "CAPI"),
KNOWN_CAPSULE("_curses", "_C_API"),
KNOWN_CAPSULE("datetime", "datetime_CAPI"),
{ NULL, NULL },
};
known_capsule *known = &known_capsules[0];
#define FAIL(x) { error = (x); goto exit; }
#define CHECK_DESTRUCTOR \
if (capsule_error) { \
FAIL(capsule_error); \
} \
else if (!capsule_destructor_call_count) { \
FAIL("destructor not called!"); \
} \
capsule_destructor_call_count = 0; \
object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor);
PyCapsule_SetContext(object, capsule_context);
capsule_destructor(object);
CHECK_DESTRUCTOR;
Py_DECREF(object);
CHECK_DESTRUCTOR;
object = PyCapsule_New(known, "ignored", NULL);
PyCapsule_SetPointer(object, capsule_pointer);
PyCapsule_SetName(object, capsule_name);
PyCapsule_SetDestructor(object, capsule_destructor);
PyCapsule_SetContext(object, capsule_context);
capsule_destructor(object);
CHECK_DESTRUCTOR;
/* intentionally access using the wrong name */
pointer2 = PyCapsule_GetPointer(object, "the wrong name");
if (!PyErr_Occurred()) {
FAIL("PyCapsule_GetPointer should have failed but did not!");
}
PyErr_Clear();
if (pointer2) {
if (pointer2 == capsule_pointer) {
FAIL("PyCapsule_GetPointer should not have"
" returned the internal pointer!");
} else {
FAIL("PyCapsule_GetPointer should have "
"returned NULL pointer but did not!");
}
}
PyCapsule_SetDestructor(object, NULL);
Py_DECREF(object);
if (capsule_destructor_call_count) {
FAIL("destructor called when it should not have been!");
}
for (known = &known_capsules[0]; known->module != NULL; known++) {
/* yeah, ordinarily I wouldn't do this either,
but it's fine for this test harness.
*/
static char buffer[256];
#undef FAIL
#define FAIL(x) \
{ \
sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \
x, known->module, known->attribute); \
error = buffer; \
goto exit; \
} \
PyObject *module = PyImport_ImportModule(known->module);
if (module) {
pointer = PyCapsule_Import(known->name, 0);
if (!pointer) {
Py_DECREF(module);
FAIL("PyCapsule_GetPointer returned NULL unexpectedly!");
}
object = PyObject_GetAttrString(module, known->attribute);
if (!object) {
Py_DECREF(module);
return NULL;
}
pointer2 = PyCapsule_GetPointer(object,
"weebles wobble but they don't fall down");
if (!PyErr_Occurred()) {
Py_DECREF(object);
Py_DECREF(module);
FAIL("PyCapsule_GetPointer should have failed but did not!");
}
PyErr_Clear();
if (pointer2) {
Py_DECREF(module);
Py_DECREF(object);
if (pointer2 == pointer) {
FAIL("PyCapsule_GetPointer should not have"
" returned its internal pointer!");
} else {
FAIL("PyCapsule_GetPointer should have"
" returned NULL pointer but did not!");
}
}
Py_DECREF(object);
Py_DECREF(module);
}
else
PyErr_Clear();
}
exit:
if (error) {
return raiseTestError("test_capsule", error);
}
Py_RETURN_NONE;
#undef FAIL
}
/* This is here to provide a docstring for test_descr. */
static PyObject *
test_with_docstring(PyObject *self)
@ -1539,6 +1690,7 @@ static PyMethodDef TestMethods[] = {
{"_test_thread_state", test_thread_state, METH_VARARGS},
{"_pending_threadfunc", pending_threadfunc, METH_VARARGS},
#endif
{"test_capsule", (PyCFunction)test_capsule, METH_NOARGS},
{"traceback_print", traceback_print, METH_VARARGS},
{"code_newempty", code_newempty, METH_VARARGS},
{"make_exception_with_doc", (PyCFunction)make_exception_with_doc,

View File

@ -761,8 +761,8 @@ initcStringIO(void) {
Py_TYPE(&Otype)=&PyType_Type;
if (PyType_Ready(&Otype) < 0) return;
if (PyType_Ready(&Itype) < 0) return;
PyDict_SetItemString(d,"cStringIO_CAPI",
v = PyCObject_FromVoidPtr(&CAPI,NULL));
v = PyCapsule_New(&CAPI, PycStringIO_CAPSULE_NAME, NULL);
PyDict_SetItemString(d,"cStringIO_CAPI", v);
Py_XDECREF(v);
/* Export Types */

View File

@ -282,7 +282,7 @@ getcodec(PyObject *self, PyObject *encoding)
return NULL;
}
codecobj = PyCObject_FromVoidPtr((void *)codec, NULL);
codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL);
if (codecobj == NULL)
return NULL;
@ -307,7 +307,7 @@ register_maps(PyObject *module)
int r;
strcpy(mhname + sizeof("__map_") - 1, h->charset);
r = PyModule_AddObject(module, mhname,
PyCObject_FromVoidPtr((void *)h, NULL));
PyCapsule_New((void *)h, PyMultibyteCodec_CAPSULE_NAME, NULL));
if (r == -1)
return -1;
}
@ -362,14 +362,14 @@ importmap(const char *modname, const char *symbol,
o = PyObject_GetAttrString(mod, (char*)symbol);
if (o == NULL)
goto errorexit;
else if (!PyCObject_Check(o)) {
else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) {
PyErr_SetString(PyExc_ValueError,
"map data must be a CObject.");
"map data must be a Capsule.");
goto errorexit;
}
else {
struct dbcs_map *map;
map = PyCObject_AsVoidPtr(o);
map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME);
if (encmap != NULL)
*encmap = map->encmap;
if (decmap != NULL)

View File

@ -1774,12 +1774,12 @@ __create_codec(PyObject *ignore, PyObject *arg)
MultibyteCodecObject *self;
MultibyteCodec *codec;
if (!PyCObject_Check(arg)) {
if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) {
PyErr_SetString(PyExc_ValueError, "argument type invalid");
return NULL;
}
codec = PyCObject_AsVoidPtr(arg);
codec = PyCapsule_GetPointer(arg, PyMultibyteCodec_CAPSULE_NAME);
if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0)
return NULL;

View File

@ -132,6 +132,9 @@ typedef struct {
#define MBENC_FLUSH 0x0001 /* encode all characters encodable */
#define MBENC_MAX MBENC_FLUSH
#define PyMultibyteCodec_CAPSULE_NAME "multibytecodec.__map_*"
#ifdef __cplusplus
}
#endif

View File

@ -4856,11 +4856,10 @@ initdatetime(void)
Py_INCREF(&PyDateTime_TZInfoType);
PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);
x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC,
NULL);
if (x == NULL)
return;
PyModule_AddObject(m, "datetime_CAPI", x);
x = PyCapsule_New(&CAPI, PyDateTime_CAPSULE_NAME, NULL);
if (x == NULL)
return NULL;
PyModule_AddObject(m, "datetime_CAPI", x);
/* A 4-year cycle has an extra leap day over what we'd get from
* pasting together 4 single years.

View File

@ -2053,8 +2053,8 @@ MODULE_INITFUNC(void)
capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler;
capi.SetUserData = XML_SetUserData;
/* export as cobject */
capi_object = PyCObject_FromVoidPtr(&capi, NULL);
/* export using capsule */
capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL);
if (capi_object)
PyModule_AddObject(m, "expat_CAPI", capi_object);
}

View File

@ -4496,7 +4496,7 @@ init_socket(void)
/* Export C API */
if (PyModule_AddObject(m, PySocket_CAPI_NAME,
PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL)
PyCapsule_New(&PySocketModuleAPI, PySocket_CAPSULE_NAME, NULL)
) != 0)
return;

View File

@ -78,6 +78,7 @@ extern "C" {
/* Python module and C API name */
#define PySocket_MODULE_NAME "_socket"
#define PySocket_CAPI_NAME "CAPI"
#define PySocket_CAPSULE_NAME (PySocket_MODULE_NAME "." PySocket_CAPI_NAME)
/* Abstract the socket file descriptor type */
#ifdef MS_WINDOWS
@ -142,12 +143,12 @@ typedef struct {
the _socket module. Since cross-DLL linking introduces a lot of
problems on many platforms, the "trick" is to wrap the
C API of a module in a struct which then gets exported to
other modules via a PyCObject.
other modules via a PyCapsule.
The code in socketmodule.c defines this struct (which currently
only contains the type object reference, but could very
well also include other C APIs needed by other modules)
and exports it as PyCObject via the module dictionary
and exports it as PyCapsule via the module dictionary
under the name "CAPI".
Other modules can now include the socketmodule.h file
@ -226,33 +227,18 @@ PySocketModule_APIObject PySocketModule;
static
int PySocketModule_ImportModuleAndAPI(void)
{
PyObject *mod = 0, *v = 0;
char *apimodule = PySocket_MODULE_NAME;
char *apiname = PySocket_CAPI_NAME;
void *api;
DPRINTF("Importing the %s C API...\n", apimodule);
mod = PyImport_ImportModuleNoBlock(apimodule);
if (mod == NULL)
goto onError;
DPRINTF(" %s package found\n", apimodule);
v = PyObject_GetAttrString(mod, apiname);
if (v == NULL)
goto onError;
Py_DECREF(mod);
DPRINTF(" API object %s found\n", apiname);
api = PyCObject_AsVoidPtr(v);
DPRINTF(" Loading capsule %s\n", PySocket_CAPSULE_NAME);
api = PyCapsule_Import(PySocket_CAPSULE_NAME, 1);
if (api == NULL)
goto onError;
Py_DECREF(v);
memcpy(&PySocketModule, api, sizeof(PySocketModule));
DPRINTF(" API object loaded and initialized.\n");
return 0;
onError:
DPRINTF(" not found.\n");
Py_XDECREF(mod);
Py_XDECREF(v);
return -1;
}

View File

@ -1261,7 +1261,7 @@ initunicodedata(void)
PyModule_AddObject(m, "ucd_3_2_0", v);
/* Export C API */
v = PyCObject_FromVoidPtr((void *) &hashAPI, NULL);
v = PyCapsule_New((void *)&hashAPI, PyUnicodeData_CAPSULE_NAME, NULL);
if (v != NULL)
PyModule_AddObject(m, "ucnhash_CAPI", v);
}

324
Objects/capsule.c Normal file
View File

@ -0,0 +1,324 @@
/* Wrap void * pointers to be passed between C modules */
#include "Python.h"
/* Internal structure of PyCapsule */
typedef struct {
PyObject_HEAD
void *pointer;
const char *name;
void *context;
PyCapsule_Destructor destructor;
} PyCapsule;
static int
_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
{
if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
PyErr_SetString(PyExc_ValueError, invalid_capsule);
return 0;
}
return 1;
}
#define is_legal_capsule(capsule, name) \
(_is_legal_capsule(capsule, \
name " called with invalid PyCapsule object"))
static int
name_matches(const char *name1, const char *name2) {
/* if either is NULL, */
if (!name1 || !name2) {
/* they're only the same if they're both NULL. */
return name1 == name2;
}
return !strcmp(name1, name2);
}
PyObject *
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
{
PyCapsule *capsule;
if (!pointer) {
PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
return NULL;
}
capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
if (capsule == NULL) {
return NULL;
}
capsule->pointer = pointer;
capsule->name = name;
capsule->context = NULL;
capsule->destructor = destructor;
return (PyObject *)capsule;
}
int
PyCapsule_IsValid(PyObject *o, const char *name)
{
PyCapsule *capsule = (PyCapsule *)o;
return (capsule != NULL &&
PyCapsule_CheckExact(capsule) &&
capsule->pointer != NULL &&
name_matches(capsule->name, name));
}
void *
PyCapsule_GetPointer(PyObject *o, const char *name)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
return NULL;
}
if (!name_matches(name, capsule->name)) {
PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
return NULL;
}
return capsule->pointer;
}
const char *
PyCapsule_GetName(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
return NULL;
}
return capsule->name;
}
PyCapsule_Destructor
PyCapsule_GetDestructor(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
return NULL;
}
return capsule->destructor;
}
void *
PyCapsule_GetContext(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
return NULL;
}
return capsule->context;
}
int
PyCapsule_SetPointer(PyObject *o, void *pointer)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!pointer) {
PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
return -1;
}
if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
return -1;
}
capsule->pointer = pointer;
return 0;
}
int
PyCapsule_SetName(PyObject *o, const char *name)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
return -1;
}
capsule->name = name;
return 0;
}
int
PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
return -1;
}
capsule->destructor = destructor;
return 0;
}
int
PyCapsule_SetContext(PyObject *o, void *context)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
return -1;
}
capsule->context = context;
return 0;
}
void *
PyCapsule_Import(const char *name, int no_block)
{
PyObject *object = NULL;
void *return_value = NULL;
char *trace;
size_t name_length = (strlen(name) + 1) * sizeof(char);
char *name_dup = (char *)PyMem_MALLOC(name_length);
if (!name_dup) {
return NULL;
}
memcpy(name_dup, name, name_length);
trace = name_dup;
while (trace) {
char *dot = strchr(trace, '.');
if (dot) {
*dot++ = '\0';
}
if (object == NULL) {
if (no_block) {
object = PyImport_ImportModuleNoBlock(trace);
} else {
object = PyImport_ImportModule(trace);
if (!object) {
PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
}
}
} else {
PyObject *object2 = PyObject_GetAttrString(object, trace);
Py_DECREF(object);
object = object2;
}
if (!object) {
goto EXIT;
}
trace = dot;
}
/* compare attribute name to module.name by hand */
if (PyCapsule_IsValid(object, name)) {
PyCapsule *capsule = (PyCapsule *)object;
return_value = capsule->pointer;
} else {
PyErr_Format(PyExc_AttributeError,
"PyCapsule_Import \"%s\" is not valid",
name);
}
EXIT:
Py_XDECREF(object);
if (name_dup) {
PyMem_FREE(name_dup);
}
return return_value;
}
static void
capsule_dealloc(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (capsule->destructor) {
capsule->destructor(o);
}
PyObject_DEL(o);
}
static PyObject *
capsule_repr(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
const char *name;
const char *quote;
if (capsule->name) {
quote = "\"";
name = capsule->name;
} else {
quote = "";
name = "NULL";
}
return PyString_FromFormat("<capsule object %s%s%s at %p>",
quote, name, quote, capsule);
}
PyDoc_STRVAR(PyCapsule_Type__doc__,
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
object. They're a way of passing data through the Python interpreter\n\
without creating your own custom type.\n\
\n\
Capsules are used for communication between extension modules.\n\
They provide a way for an extension module to export a C interface\n\
to other extension modules, so that extension modules can use the\n\
Python import mechanism to link to one another.\n\
");
PyTypeObject PyCapsule_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"PyCapsule", /*tp_name*/
sizeof(PyCapsule), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
capsule_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_reserved*/
capsule_repr, /*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*/
PyCapsule_Type__doc__ /*tp_doc*/
};

View File

@ -2269,6 +2269,10 @@ _Py_GetObjects(PyObject *self, PyObject *args)
#endif
/* Hack to force loading of capsule.o */
PyTypeObject *_Py_capsule_hack = &PyCapsule_Type;
/* Hack to force loading of cobject.o */
PyTypeObject *_Py_cobject_hack = &PyCObject_Type;

View File

@ -2889,16 +2889,7 @@ PyObject *PyUnicode_DecodeUnicodeEscape(const char *s,
message = "malformed \\N character escape";
if (ucnhash_CAPI == NULL) {
/* load the unicode data module */
PyObject *m, *api;
m = PyImport_ImportModuleNoBlock("unicodedata");
if (m == NULL)
goto ucnhashError;
api = PyObject_GetAttrString(m, "ucnhash_CAPI");
Py_DECREF(m);
if (api == NULL)
goto ucnhashError;
ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCObject_AsVoidPtr(api);
Py_DECREF(api);
ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCapsule_Import(PyUnicodeData_CAPSULE_NAME, 1);
if (ucnhash_CAPI == NULL)
goto ucnhashError;
}

View File

@ -460,6 +460,9 @@
<File
RelativePath="..\..\Objects\bytes_methods.c">
</File>
<File
RelativePath="..\..\Objects\capsule.c">
</File>
<File
RelativePath="..\..\Objects\cellobject.c">
</File>

View File

@ -854,6 +854,10 @@
RelativePath="..\..\Include\pyarena.h"
>
</File>
<File
RelativePath="..\..\Include\pycapsule.h"
>
</File>
<File
RelativePath="..\..\Include\pyctype.h"
>
@ -1418,6 +1422,10 @@
RelativePath="..\..\Objects\stringobject.c"
>
</File>
<File
RelativePath="..\..\Objects\capsule.c"
>
</File>
<File
RelativePath="..\..\Objects\cellobject.c"
>

View File

@ -210,6 +210,19 @@ EXPORTS
"PyInstance_Type"
"PyMethod_Type"
; From python27_s.lib(capsule)
"PyCapsule_GetContext"
"PyCapsule_GetDestructor"
"PyCapsule_GetName"
"PyCapsule_GetPointer"
"PyCapsule_Import"
"PyCapsule_IsValid"
"PyCapsule_New"
"PyCapsule_SetContext"
"PyCapsule_SetDestructor"
"PyCapsule_SetName"
"PyCapsule_SetPointer"
; From python27_s.lib(cobject)
"PyCObject_FromVoidPtr"
"PyCObject_FromVoidPtrAndDesc"

View File

@ -6,6 +6,7 @@ DATA MULTIPLE NONSHARED
EXPORTS
; Data
PyCFunction_Type
PyCapsule_Type
PyCObject_Type
PyClass_Type
PyCode_Type
@ -75,6 +76,7 @@ EXPORTS
_Py_TrueStruct
_Py_ZeroStruct
_Py_abstract_hack
_Py_capsule_hack
_Py_cobject_hack
_Py_re_syntax
_Py_re_syntax_table
@ -89,6 +91,17 @@ EXPORTS
PyCFunction_GetFunction
PyCFunction_GetSelf
PyCFunction_New
PyCapsule_GetContext
PyCapsule_GetDestructor
PyCapsule_GetName
PyCapsule_GetPointer
PyCapsule_Import
PyCapsule_IsValid
PyCapsule_New
PyCapsule_SetContext
PyCapsule_SetDestructor
PyCapsule_SetName
PyCapsule_SetPointer
PyCObject_AsVoidPtr
PyCObject_FromVoidPtrAndDesc
PyCObject_FromVoidPtr

View File

@ -181,6 +181,8 @@ static int compiler_with(struct compiler *, stmt_ty);
static PyCodeObject *assemble(struct compiler *, int addNone);
static PyObject *__doc__;
#define COMPILER_CAPSULE_NAME_COMPILER_UNIT "compile.c compiler unit"
PyObject *
_Py_Mangle(PyObject *privateobj, PyObject *ident)
{
@ -490,13 +492,13 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
/* Push the old compiler_unit on the stack. */
if (c->u) {
PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL);
if (!wrapper || PyList_Append(c->c_stack, wrapper) < 0) {
Py_XDECREF(wrapper);
PyObject *capsule = PyCapsule_New(c->u, COMPILER_CAPSULE_NAME_COMPILER_UNIT, NULL);
if (!capsule || PyList_Append(c->c_stack, capsule) < 0) {
Py_XDECREF(capsule);
compiler_unit_free(u);
return 0;
}
Py_DECREF(wrapper);
Py_DECREF(capsule);
u->u_private = c->u->u_private;
Py_XINCREF(u->u_private);
}
@ -513,15 +515,15 @@ static void
compiler_exit_scope(struct compiler *c)
{
int n;
PyObject *wrapper;
PyObject *capsule;
c->c_nestlevel--;
compiler_unit_free(c->u);
/* Restore c->u to the parent unit. */
n = PyList_GET_SIZE(c->c_stack) - 1;
if (n >= 0) {
wrapper = PyList_GET_ITEM(c->c_stack, n);
c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper);
capsule = PyList_GET_ITEM(c->c_stack, n);
c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
assert(c->u);
/* we are deleting from a list so this really shouldn't fail */
if (PySequence_DelItem(c->c_stack, n) < 0)

View File

@ -139,22 +139,33 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
/* Handle cleanup of allocated memory in case of exception */
#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr"
#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer"
static void
cleanup_ptr(void *ptr)
cleanup_ptr(PyObject *self)
{
PyMem_FREE(ptr);
void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR);
if (ptr) {
PyMem_FREE(ptr);
}
}
static void
cleanup_buffer(void *ptr)
cleanup_buffer(PyObject *self)
{
PyBuffer_Release((Py_buffer *) ptr);
Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER);
if (ptr) {
PyBuffer_Release(ptr);
}
}
static int
addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr)
{
PyObject *cobj;
const char *name;
if (!*freelist) {
*freelist = PyList_New(0);
if (!*freelist) {
@ -162,7 +173,15 @@ addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
return -1;
}
}
cobj = PyCObject_FromVoidPtr(ptr, destr);
if (destr == cleanup_ptr) {
name = GETARGS_CAPSULE_NAME_CLEANUP_PTR;
} else if (destr == cleanup_buffer) {
name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER;
} else {
return -1;
}
cobj = PyCapsule_New(ptr, name, destr);
if (!cobj) {
destr(ptr);
return -1;
@ -183,8 +202,7 @@ cleanreturn(int retval, PyObject *freelist)
don't get called. */
Py_ssize_t len = PyList_GET_SIZE(freelist), i;
for (i = 0; i < len; i++)
((PyCObject *) PyList_GET_ITEM(freelist, i))
->destructor = NULL;
PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL);
}
Py_XDECREF(freelist);
return retval;