Renamed everything from 'fixed buffer' to 'locked buffer'.

Recommandations on how to implement the interface.
This commit is contained in:
Thomas Heller 2002-08-01 18:24:06 +00:00
parent 419b7d99fb
commit 7fadff7e8a
1 changed files with 83 additions and 48 deletions

View File

@ -1,5 +1,5 @@
PEP: 298
Title: The Fixed Buffer Interface
Title: The Locked Buffer Interface
Version: $Revision$
Last-Modified: $Date$
Author: Thomas Heller <theller@python.net>
@ -7,15 +7,15 @@ Status: Draft
Type: Standards Track
Created: 26-Jul-2002
Python-Version: 2.3
Post-History: 30-Jul-2002
Post-History: 30-Jul-2002, 1-Aug-2002
Abstract
This PEP proposes an extension to the buffer interface called the
'fixed buffer interface'.
'locked buffer interface'.
The fixed buffer interface fixes the flaws of the 'old' buffer
The locked buffer interface avoids the flaws of the 'old' buffer
interface [1] as defined in Python versions up to and including
2.2, and has the following semantics:
@ -33,7 +33,7 @@ Abstract
Specification
The fixed buffer interface exposes new functions which return the
The locked buffer interface exposes new functions which return the
size and the pointer to the internal memory block of any python
object which chooses to implement this interface.
@ -42,31 +42,31 @@ Specification
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
no longer used by calling another function in the locked buffer
interface. If the object never resizes or reallocates the buffer
during it's lifetime, this function may be NULL. Failure to call
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.
The fixed buffer interface omits the memory segment model which is
present in the old buffer interface - only a single memory block
can be exposed.
The locked buffer interface omits the memory segment model which
is present in the old buffer interface - only a single memory
block can be exposed.
Implementation
Define a new flag in Include/object.h:
/* PyBufferProcs contains bf_acquirefixedreadbuffer,
bf_acquirefixedwritebuffer, and bf_releasefixedbuffer */
#define Py_TPFLAGS_HAVE_FIXEDBUFFER (1L<<15)
/* PyBufferProcs contains bf_acquirelockedreadbuffer,
bf_acquirelockedwritebuffer, and bf_releaselockedbuffer */
#define Py_TPFLAGS_HAVE_LOCKEDBUFFER (1L<<15)
This flag would be included in Py_TPFLAGS_DEFAULT:
#define Py_TPFLAGS_DEFAULT ( \
....
Py_TPFLAGS_HAVE_FIXEDBUFFER | \
Py_TPFLAGS_HAVE_LOCKEDBUFFER | \
....
0)
@ -74,31 +74,31 @@ Implementation
Extend the PyBufferProcs structure by new fields in
Include/object.h:
typedef size_t (*acquirefixedreadbufferproc)(PyObject *,
const void **);
typedef size_t (*acquirefixedwritebufferproc)(PyObject *,
void **);
typedef void (*releasefixedbufferproc)(PyObject *);
typedef size_t (*acquirelockedreadbufferproc)(PyObject *,
const void **);
typedef size_t (*acquirelockedwritebufferproc)(PyObject *,
void **);
typedef void (*releaselockedbufferproc)(PyObject *);
typedef struct {
getreadbufferproc bf_getreadbuffer;
getwritebufferproc bf_getwritebuffer;
getsegcountproc bf_getsegcount;
getcharbufferproc bf_getcharbuffer;
/* fixed buffer interface functions */
acquirefixedreadbufferproc bf_acquirefixedreadbuffer;
acquirefixedwritebufferproc bf_acquirefixedwritebuffer;
releasefixedbufferproc bf_releasefixedbuffer;
getreadbufferproc bf_getreadbuffer;
getwritebufferproc bf_getwritebuffer;
getsegcountproc bf_getsegcount;
getcharbufferproc bf_getcharbuffer;
/* locked buffer interface functions */
acquirelockedreadbufferproc bf_acquirelockedreadbuffer;
acquirelockedwritebufferproc bf_acquirelockedwritebuffer;
releaselockedbufferproc bf_releaselockedbuffer;
} PyBufferProcs;
The new fields are present if the Py_TPFLAGS_HAVE_FIXEDBUFFER
The new fields are present if the Py_TPFLAGS_HAVE_LOCKEDBUFFER
flag is set in the object's type.
The Py_TPFLAGS_HAVE_FIXEDBUFFER flag implies the
The Py_TPFLAGS_HAVE_LOCKEDBUFFER flag implies the
Py_TPFLAGS_HAVE_GETCHARBUFFER flag.
The acquirefixedreadbufferproc and acquirefixedwritebufferproc
The acquirelockedreadbufferproc and acquirelockedwritebufferproc
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
@ -107,26 +107,36 @@ Implementation
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.
released by a call to the releaselockedbufferproc, supplying the
original object as argument. The releaselockedbufferproc cannot
fail. For objects that actually maintain an internal lock count
it would be a fatal error if the releaselockedbufferproc function
would be called too often, leading to a negative lock count.
Usually these functions aren't called directly, they are called
through convenience functions declared in Include/abstract.h:
Similar to the 'old' buffer interface, any of these functions may
be set to NULL, but it is strongly recommended to implement the
releaselockedbufferproc function (even if it does nothing) if any
of the acquireread/writelockedbufferproc functions are
implemented, to discourage extension writers from checking for a
NULL value and not calling it.
int PyObject_AquireFixedReadBuffer(PyObject *obj,
const void **buffer,
size_t *buffer_len);
These functions aren't supposed to be called directly, they are
called through convenience functions declared in
Include/abstract.h:
int PyObject_AcquireFixedWriteBuffer(PyObject *obj,
void **buffer,
size_t *buffer_len);
int PyObject_AquireLockedReadBuffer(PyObject *obj,
const void **buffer,
size_t *buffer_len);
void PyObject_ReleaseFixedBuffer(PyObject *obj);
int PyObject_AcquireLockedWriteBuffer(PyObject *obj,
void **buffer,
size_t *buffer_len);
void PyObject_ReleaseLockedBuffer(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
in bytes. On failure, or if the locked buffer interface is not
implemented by obj, they return -1 and set an exception.
The latter function doesn't return anything, and cannot fail.
@ -146,13 +156,40 @@ Reference Implementation
Additional Notes/Comments
Python strings, Unicode strings, mmap objects, and array objects
would expose the fixed buffer interface.
Python strings, unicode strings, mmap objects, and array objects
would expose the locked buffer interface.
mmap and array objects would actually enter a locked state while
the buffer is active, this is not needed for strings and unicode
objects. Resizing locked array objects is not allowed and will
raise an exception. Whether closing a locked mmap object is an
error or will only be deferred until the lock count reaches zero
is an implementation detail.
Guido recommends:
But I'm still very concerned that if most built-in types
(e.g. strings, bytes) don't implement the release
functionality, it's too easy for an extension to seem to work
while forgetting to release the buffer.
I recommend that at least some built-in types implement the
acquire/release functionality with a counter, and assert that
the counter is zero when the object is deleted -- if the
assert fails, someone DECREF'ed their reference to the object
without releasing it. (The rule should be that you must own a
reference to the object while you've aquired the object.)
For strings that might be impractical because the string
object would have to grow 4 bytes to hold the counter; but the
new bytes object (PEP 296) could easily implement the counter,
and the array object too -- that way there will be plenty of
opportunity to test proper use of the protocol.
Community Feedback
Greg Ewing doubts the fixed buffer interface is needed at all, he
Greg Ewing doubts the locked buffer interface is needed at all, he
thinks the normal buffer interface could be used if the pointer is
(re)fetched each time it's used. This seems to be dangerous,
because even innocent looking calls to the Python API like
@ -167,8 +204,6 @@ Community Feedback
Credits
Scott Gilbert came up with the name 'fixed buffer interface'.
References