Travis Oliphant <oliphant.travis <at> ieee.org> writes:
> This should be clarified in the PEP.  Can you take a stab at it?

Here's a patch for what I think the locking protocol part should look like. It
changes the "passing NULL as Py_buffer" bit into a requirement to always pass a
Py_buffer structure, and distinguishes the two cases where you set LOCK and pass
either a NULL buf pointer or a valid buf pointer into getbuffer.

It also adds a new UNLOCK flag for an explicit unlock without invalidating the
Py_buffer view. The idea it that the provider can (!) decide to return different
buffers for locked and non-locked access and can switch between the two during a
call to getbuffer. That matches the existing section about copying buffers
somewhere near the end.

Stefan


Index: pep-3118.txt
===================================================================
--- pep-3118.txt        (Revision 63861)
+++ pep-3118.txt        (Arbeitskopie)
@@ -153,10 +153,8 @@
 
 This function returns ``0`` on success and ``-1`` on failure (and raises an
 error). The first variable is the "exporting" object.  The second
-argument is the address to a bufferinfo structure.  If view is ``NULL``,
-then no information is returned but a lock on the memory is still
-obtained.  In this case, the corresponding releasebuffer should also
-be called with ``NULL``.  
+argument is the address to a bufferinfo structure.  Both arguments must
+never be NULL.
 
 The third argument indicates what kind of buffer the consumer is
 prepared to deal with and therefore what kind of buffer the exporter
@@ -178,6 +176,19 @@
 structure (with defaults or NULLs if nothing else is requested). The
 PyBuffer_FillInfo function can be used for simple cases.
 
+The second function is called to release the Py_buffer view, which may
+allow the provider to clean up the buffer itself::
+
+    typedef void (*releasebufferproc)(Py_buffer *view)
+
+Any existing lock on the buffer will be released by this call.  The
+Py_buffer struct will be invalidated and can no longer be used by the
+caller.
+
+
+Access flags
+------------
+
 Some flags are useful for requesting a specific kind of memory
 segment, while others indicate to the exporter what kind of
 information the consumer can deal with.  If certain information is not
@@ -185,14 +196,6 @@
 without that information, then a ``PyErr_BufferError`` should be raised.
 
 
-``PyBUF_SIMPLE``
-
-   This is the default flag state (0). The returned buffer may or may
-   not have writable memory.  The format will be assumed to be
-   unsigned bytes .  This is a "stand-alone" flag constant.  It never
-   needs to be \|'d to the others.  The exporter will raise an error if
-   it cannot provide such a contiguous buffer of bytes.
-
 ``PyBUF_WRITABLE``
 
    The returned buffer must be writable.  If it is not writable,
@@ -221,6 +224,54 @@
    necessary (especially the exclusive write lock) as it makes the
    object unable to share its memory until the lock is released.
 
+   The ``PyBUF_LOCK`` flag is the only case where a Py_buffer struct
+   with an initialised ``buf`` field can be passed.  This enables two
+   general locking cases:
+
+   * lock a new buffer: The caller requests a lock at the same time as
+     requesting the buffer (i.e. ``buf`` is NULL), in an atomic
+     operation.
+
+   * lock an existing buffer: The caller has already received a buffer
+     view and now wants to gain a lock on the existing buffer (i.e.
+     ``buf`` is a valid buffer pointer).  Note that the provider is
+     free to change the ``buf`` pointer during this call, so the
+     previously used buffer may become invalid.
+
+   If the call succeeds, this means that the consumer now has the
+   exclusive requested rights on the buffer.  The lock can be released
+   by either calling ``releasebuffer`` on the Py_buffer, or by
+   explicitly releasing the lock in a subsequent call to ``getbuffer``
+   that sets the ``PyBUF_UNLOCK`` flag.
+
+``PyBUF_UNLOCK``
+
+   This flag requests to release the lock on an existing buffer, while
+   keeping the Py_buffer view alive.  The ``buf`` field must be
+   initialised by a previous call to ``getbuffer`` and should have
+   been locked before (if is not an error if the buffer is not
+   currently locked).  Similar to the LOCK call, the provider may
+   decide to change the ``buf`` field in this case, so the previous
+   buffer may become invalid.
+
+   The provider is free to ignore any flags except for the WRITABLE
+   flag, so the caller cannot request a new buffer layout with an
+   UNLOCK call.  If the WRITABLE flag is set, only an existing
+   exclusive write lock will be released, but an existing read lock
+   will be kept.  No new locks can be acquired with an UNLOCK call.
+
+
+Memory layout flags
+-------------------
+
+``PyBUF_SIMPLE``
+
+   This is the default flag state (0). The returned buffer may or may
+   not have writable memory.  The format will be assumed to be
+   unsigned bytes .  This is a "stand-alone" flag constant.  It never
+   needs to be \|'d to the others.  The exporter will raise an error if
+   it cannot provide such a contiguous buffer of bytes.
+
 ``PyBUF_FORMAT``
         
    The returned buffer must have true format information if this flag
@@ -256,7 +307,6 @@
    All of these flags imply PyBUF_STRIDES and guarantee that the
    strides buffer info structure will be filled in correctly. 
 
-
 ``PyBUF_INDIRECT`` (implies ``PyBUF_STRIDES``)
 
    The returned buffer must have suboffsets information (which can be
@@ -307,6 +357,10 @@
 buffer info structure correctly according to the provided flags if a
 contiguous chunk of "unsigned bytes" is all that can be exported.
 
+
+The Py_buffer struct
+--------------------
+
 The bufferinfo structure is::
 
   struct bufferinfo {
@@ -322,14 +376,15 @@
        void *internal;
   } Py_buffer;
 
-Before calling the bf_getbuffer function, the bufferinfo structure can be 
-filled with whatever.  Upon return from bf_getbuffer, the bufferinfo
-structure is filled in with relevant information about the buffer.
-This same bufferinfo structure must be passed to bf_releasebuffer (if
-available) when the consumer is done with the memory. The caller is
-responsible for keeping a reference to obj until releasebuffer is
-called (i.e. the call to bf_getbuffer does not alter the reference
-count of obj).
+Before calling the bf_getbuffer function, the bufferinfo structure can
+be filled with whatever, but the ``buf`` field must be NULL when
+requesting a new buffer.  Upon return from bf_getbuffer, the
+bufferinfo structure is filled in with relevant information about the
+buffer.  This same bufferinfo structure must be passed to
+bf_releasebuffer (if available) when the consumer is done with the
+memory. The caller is responsible for keeping a reference to obj until
+releasebuffer is called (i.e. the call to bf_getbuffer does not alter
+the reference count of obj).
 
 The members of the bufferinfo structure are:
 
@@ -344,13 +399,13 @@
 ``readonly``
     an integer variable to hold whether or not the memory is readonly.
     1 means the memory is readonly, zero means the memory is writable,
-    -1 means the memory was read "locked" when this Py_buffer
-    structure was filled-in therefore should be unlocked when this
-    Py_buffer structure is "released." A -2 means this Py_buffer
-    structure has an exclusive-write lock on the memory.  This should
-    be unlocked when the Py_buffer structure is released.  The concept
-    of locking is not supported by all objects that expose the buffer 
-    protocol. 
+    -1 means the memory was read "locked" either when this Py_buffer
+    structure was filled-in or later on with an explicit LOCK flag,
+    therefore should be unlocked when this Py_buffer structure is
+    "released".  A -2 means this Py_buffer structure has an
+    exclusive-write lock on the memory.  This should be unlocked when
+    the Py_buffer structure is released.  The concept of locking is
+    not supported by all objects that expose the buffer protocol.
 
 ``format``
     a NULL-terminated format-string (following the struct-style syntax
@@ -571,7 +626,7 @@
 ::
 
     PyObject * PyMemoryView_GetContiguous(PyObject *obj,  int buffertype, 
-                                          char fort)
+                                          char fortran)
 
 Return a memoryview object to a contiguous chunk of memory represented
 by obj. If a copy must be made (because the memory pointed to by obj
@@ -818,10 +873,10 @@
 
 The proposed locking mechanism relies entirely on the exporter object
 to not invalidate any of the memory pointed to by the buffer structure
-until a corresponding releasebuffer is called.  If it wants to be able
-to change its own shape and/or strides arrays, then it needs to create
-memory for these in the bufferinfo structure and copy information
-over.
+until a corresponding releasebuffer is called or the UNLOCK flag is
+passed to a getbuffer call.  If it wants to be able to change its own
+shape and/or strides arrays, then it needs to create memory for these
+in the bufferinfo structure and copy information over.
 
 The sharing of strided memory and suboffsets is new and can be seen as
 a modification of the multiple-segment interface.  It is motivated by


_______________________________________________
Python-3000 mailing list
Python-3000@python.org
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe: 
http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com

Reply via email to