2002-07-29 14:22:09 -04:00
|
|
|
|
PEP: 298
|
2002-07-30 12:41:04 -04:00
|
|
|
|
Title: The Fixed Buffer Interface
|
2002-07-29 14:22:09 -04:00
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
2002-07-30 12:41:04 -04:00
|
|
|
|
Author: Thomas Heller <theller@python.net>
|
2002-07-29 14:22:09 -04:00
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Created: 26-Jul-2002
|
|
|
|
|
Python-Version: 2.3
|
2002-07-31 14:48:36 -04:00
|
|
|
|
Post-History: 30-Jul-2002
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
|
|
|
|
|
This PEP proposes an extension to the buffer interface called the
|
2002-07-30 12:41:04 -04:00
|
|
|
|
'fixed buffer interface'.
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
2002-07-30 12:41:04 -04:00
|
|
|
|
The fixed buffer interface fixes the flaws of the 'old' buffer
|
2002-07-31 14:48:36 -04:00
|
|
|
|
interface [1] as defined in Python versions up to and including
|
|
|
|
|
2.2, and has the following semantics:
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
The lifetime of the retrieved pointer is clearly defined and
|
|
|
|
|
controlled by the client.
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
The buffer size is returned as a 'size_t' data type, which
|
|
|
|
|
allows access to large buffers on platforms where sizeof(int)
|
|
|
|
|
!= sizeof(void *).
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
(Guido comments: This second sounds like a change we could also
|
|
|
|
|
make to the "old" buffer interface, if we introduce another flag
|
|
|
|
|
bit that's *not* part of the default flags.)
|
|
|
|
|
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
|
2002-07-30 12:41:04 -04:00
|
|
|
|
The fixed buffer interface exposes new functions which return the
|
2002-07-29 14:22:09 -04:00
|
|
|
|
size and the pointer to the internal memory block of any python
|
|
|
|
|
object which chooses to implement this interface.
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
Retrieving a buffer from an object puts this object in a locked
|
|
|
|
|
state during which the buffer may not be freed, resized, or
|
|
|
|
|
reallocated.
|
|
|
|
|
|
|
|
|
|
The object must be unlocked again by releasing the buffer if it's
|
|
|
|
|
no longer used by calling another function in the fixed buffer
|
|
|
|
|
interface. If the object never resizes or reallocates the buffer
|
|
|
|
|
during it's lifetime, this function may be NULL. Failure to call
|
|
|
|
|
this function (if it is != NULL) is a programming error and may
|
|
|
|
|
have unexpected results.
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
2002-07-30 12:41:04 -04:00
|
|
|
|
The fixed buffer interface omits the memory segment model which is
|
2002-07-29 14:22:09 -04:00
|
|
|
|
present in the old buffer interface - only a single memory block
|
|
|
|
|
can be exposed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Implementation
|
|
|
|
|
|
|
|
|
|
Define a new flag in Include/object.h:
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
/* PyBufferProcs contains bf_acquirefixedreadbuffer,
|
|
|
|
|
bf_acquirefixedwritebuffer, and bf_releasefixedbuffer */
|
|
|
|
|
#define Py_TPFLAGS_HAVE_FIXEDBUFFER (1L<<15)
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This flag would be included in Py_TPFLAGS_DEFAULT:
|
|
|
|
|
|
|
|
|
|
#define Py_TPFLAGS_DEFAULT ( \
|
|
|
|
|
....
|
2002-07-31 14:48:36 -04:00
|
|
|
|
Py_TPFLAGS_HAVE_FIXEDBUFFER | \
|
2002-07-29 14:22:09 -04:00
|
|
|
|
....
|
|
|
|
|
0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Extend the PyBufferProcs structure by new fields in
|
|
|
|
|
Include/object.h:
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
typedef size_t (*acquirefixedreadbufferproc)(PyObject *,
|
|
|
|
|
const void **);
|
|
|
|
|
typedef size_t (*acquirefixedwritebufferproc)(PyObject *,
|
|
|
|
|
void **);
|
|
|
|
|
typedef void (*releasefixedbufferproc)(PyObject *);
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
getreadbufferproc bf_getreadbuffer;
|
|
|
|
|
getwritebufferproc bf_getwritebuffer;
|
|
|
|
|
getsegcountproc bf_getsegcount;
|
|
|
|
|
getcharbufferproc bf_getcharbuffer;
|
2002-07-30 12:41:04 -04:00
|
|
|
|
/* fixed buffer interface functions */
|
2002-07-31 14:48:36 -04:00
|
|
|
|
acquirefixedreadbufferproc bf_acquirefixedreadbuffer;
|
|
|
|
|
acquirefixedwritebufferproc bf_acquirefixedwritebuffer;
|
|
|
|
|
releasefixedbufferproc bf_releasefixedbuffer;
|
2002-07-29 14:22:09 -04:00
|
|
|
|
} PyBufferProcs;
|
|
|
|
|
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
The new fields are present if the Py_TPFLAGS_HAVE_FIXEDBUFFER
|
2002-07-29 14:22:09 -04:00
|
|
|
|
flag is set in the object's type.
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
The Py_TPFLAGS_HAVE_FIXEDBUFFER flag implies the
|
2002-07-29 14:22:09 -04:00
|
|
|
|
Py_TPFLAGS_HAVE_GETCHARBUFFER flag.
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
The acquirefixedreadbufferproc and acquirefixedwritebufferproc
|
|
|
|
|
functions return the size in bytes of the memory block on success,
|
|
|
|
|
and fill in the passed void * pointer on success. If these
|
|
|
|
|
functions fail - either because an error occurs or no memory block
|
|
|
|
|
is exposed - they must set the void * pointer to NULL and raise an
|
|
|
|
|
exception. The return value is undefined in these cases and
|
|
|
|
|
should not be used.
|
|
|
|
|
|
|
|
|
|
If calls to these functions succeed, eventually the buffer must be
|
|
|
|
|
released by a call to the releasefixedbufferproc, supplying the
|
|
|
|
|
original object as argument. The releasefixedbufferproc cannot
|
|
|
|
|
fail.
|
|
|
|
|
|
|
|
|
|
Usually these functions aren't called directly, they are called
|
|
|
|
|
through convenience functions declared in Include/abstract.h:
|
|
|
|
|
|
|
|
|
|
int PyObject_AquireFixedReadBuffer(PyObject *obj,
|
|
|
|
|
const void **buffer,
|
|
|
|
|
size_t *buffer_len);
|
|
|
|
|
|
|
|
|
|
int PyObject_AcquireFixedWriteBuffer(PyObject *obj,
|
|
|
|
|
void **buffer,
|
|
|
|
|
size_t *buffer_len);
|
|
|
|
|
|
|
|
|
|
void PyObject_ReleaseFixedBuffer(PyObject *obj);
|
|
|
|
|
|
|
|
|
|
The former two functions return 0 on success, set buffer to the
|
|
|
|
|
memory location and buffer_len to the length of the memory block
|
|
|
|
|
in bytes. On failure, or if the fixed buffer interface is not
|
2002-07-29 14:22:09 -04:00
|
|
|
|
implemented by obj, they return -1 and set an exception.
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
The latter function doesn't return anything, and cannot fail.
|
|
|
|
|
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
Backward Compatibility
|
|
|
|
|
|
|
|
|
|
The size of the PyBufferProcs structure changes if this proposal
|
|
|
|
|
is implemented, but the type's tp_flags slot can be used to
|
|
|
|
|
determine if the additional fields are present.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Reference Implementation
|
|
|
|
|
|
|
|
|
|
Will be uploaded to the SourceForge patch manager by the author.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Additional Notes/Comments
|
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
Python strings, Unicode strings, mmap objects, and array objects
|
|
|
|
|
would expose the fixed buffer interface.
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Community Feedback
|
|
|
|
|
|
2002-07-30 12:41:04 -04:00
|
|
|
|
Greg Ewing doubts the fixed buffer interface is needed at all, he
|
2002-07-29 14:22:09 -04:00
|
|
|
|
thinks the normal buffer interface could be used if the pointer is
|
2002-07-30 12:41:04 -04:00
|
|
|
|
(re)fetched each time it's used. This seems to be dangerous,
|
|
|
|
|
because even innocent looking calls to the Python API like
|
|
|
|
|
Py_DECREF() may trigger execution of arbitrary Python code.
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
2002-07-31 14:48:36 -04:00
|
|
|
|
The first version of this proposal didn't have the release
|
|
|
|
|
function, but it turned out that this would have been too
|
|
|
|
|
restrictive: mmap and array objects wouldn't have been able to
|
|
|
|
|
implement it, because mmap objects can be closed anytime if not
|
|
|
|
|
locked, and array objects could resize or reallocate the buffer.
|
2002-07-30 12:41:04 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Credits
|
|
|
|
|
|
|
|
|
|
Scott Gilbert came up with the name 'fixed buffer interface'.
|
2002-07-29 14:22:09 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
|
|
|
|
|
[1] The buffer interface
|
|
|
|
|
http://mail.python.org/pipermail/python-dev/2000-October/009974.html
|
|
|
|
|
|
|
|
|
|
[2] The Buffer Problem
|
|
|
|
|
http://www.python.org/peps/pep-0296.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
End:
|