PEP 298, The Safe Buffer Interface, Heller
This commit is contained in:
parent
1f177c83ae
commit
135eff8437
|
@ -0,0 +1,164 @@
|
|||
PEP: 298
|
||||
Title: The Safe Buffer Interface
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: theller@python.net (Thomas Heller)
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 26-Jul-2002
|
||||
Python-Version: 2.3
|
||||
Post-History:
|
||||
|
||||
|
||||
Abstract
|
||||
|
||||
This PEP proposes an extension to the buffer interface called the
|
||||
'safe buffer interface'.
|
||||
|
||||
The safe buffer interface fixes the flaws of the 'old' buffer
|
||||
interface as defined in Python versions up to and including 2.2,
|
||||
see [1]:
|
||||
|
||||
The lifetime of the retrieved pointer is clearly defined.
|
||||
|
||||
The buffer size is returned as a 'size_t' data type, which
|
||||
allows access to large buffers on platforms where sizeof(int)
|
||||
!= sizeof(void *).
|
||||
|
||||
|
||||
Specification
|
||||
|
||||
The safe 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.
|
||||
|
||||
The size and pointer returned must be valid as long as the object
|
||||
is alive (has a positive reference count). So, only objects which
|
||||
never reallocate or resize the memory block are allowed to
|
||||
implement this interface.
|
||||
|
||||
The safe 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_getsafereadbuffer
|
||||
and bf_getsafewritebuffer */
|
||||
#define Py_TPFLAGS_HAVE_GETSAFEBUFFER (1L<<15)
|
||||
|
||||
|
||||
This flag would be included in Py_TPFLAGS_DEFAULT:
|
||||
|
||||
#define Py_TPFLAGS_DEFAULT ( \
|
||||
....
|
||||
Py_TPFLAGS_HAVE_GETSAFEBUFFER | \
|
||||
....
|
||||
0)
|
||||
|
||||
|
||||
Extend the PyBufferProcs structure by new fields in
|
||||
Include/object.h:
|
||||
|
||||
typedef size_t (*getsafereadbufferproc)(PyObject *, void **);
|
||||
typedef size_t (*getsafewritebufferproc)(PyObject *, void **);
|
||||
|
||||
typedef struct {
|
||||
getreadbufferproc bf_getreadbuffer;
|
||||
getwritebufferproc bf_getwritebuffer;
|
||||
getsegcountproc bf_getsegcount;
|
||||
getcharbufferproc bf_getcharbuffer;
|
||||
/* safe buffer interface functions */
|
||||
getsafereadbufferproc bf_getsafereadbufferproc;
|
||||
getsafewritebufferproc bf_getsafewritebufferproc;
|
||||
} PyBufferProcs;
|
||||
|
||||
|
||||
The new fields are present if the Py_TPFLAGS_HAVE_GETSAFEBUFFER
|
||||
flag is set in the object's type.
|
||||
|
||||
The Py_TPFLAGS_HAVE_GETSAFEBUFFER flag implies the
|
||||
Py_TPFLAGS_HAVE_GETCHARBUFFER flag.
|
||||
|
||||
The getsafereadbufferproc and getsafewritebufferproc 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.
|
||||
|
||||
Usually the getsafewritebufferproc and getsafereadbufferproc
|
||||
functions aren't called directly, they are called through
|
||||
convenience functions declared in Include/abstract.h:
|
||||
|
||||
int PyObject_AsSafeReadBuffer(PyObject *obj,
|
||||
void **buffer,
|
||||
size_t *buffer_len);
|
||||
|
||||
int PyObject_AsSafeWriteBuffer(PyObject *obj,
|
||||
void **buffer,
|
||||
size_t *buffer_len);
|
||||
|
||||
These 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 safe buffer interface is not
|
||||
implemented by obj, they return -1 and set an exception.
|
||||
|
||||
|
||||
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
|
||||
|
||||
Python strings, Unicode strings, mmap objects, and maybe other
|
||||
types would expose the safe buffer interface, but the array type
|
||||
would *not*, because its memory block may be reallocated during
|
||||
its lifetime.
|
||||
|
||||
|
||||
Community Feedback
|
||||
|
||||
Greg Ewing doubts the safe 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.
|
||||
|
||||
Neil Hodgson wants to expose pointers to memory blocks with
|
||||
limited lifetime: do some kind of lock operation on the object,
|
||||
retrieve the pointer, use it, and unlock the object again. On the
|
||||
other hand, locking may lead to deadlocks.
|
||||
|
||||
|
||||
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:
|
Loading…
Reference in New Issue