mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-132551: make io.BytesIO thread safe (#132616)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
This commit is contained in:
parent
bd7c5859c6
commit
5dd3a3a58c
4 changed files with 356 additions and 100 deletions
109
Lib/test/test_free_threading/test_io.py
Normal file
109
Lib/test/test_free_threading/test_io.py
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import threading
|
||||||
|
from unittest import TestCase
|
||||||
|
from test.support import threading_helper
|
||||||
|
from random import randint
|
||||||
|
from io import BytesIO
|
||||||
|
from sys import getsizeof
|
||||||
|
|
||||||
|
|
||||||
|
class TestBytesIO(TestCase):
|
||||||
|
# Test pretty much everything that can break under free-threading.
|
||||||
|
# Non-deterministic, but at least one of these things will fail if
|
||||||
|
# BytesIO object is not free-thread safe.
|
||||||
|
|
||||||
|
def check(self, funcs, *args):
|
||||||
|
barrier = threading.Barrier(len(funcs))
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
for func in funcs:
|
||||||
|
thread = threading.Thread(target=func, args=(barrier, *args))
|
||||||
|
|
||||||
|
threads.append(thread)
|
||||||
|
|
||||||
|
with threading_helper.start_threads(threads):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
|
@threading_helper.reap_threads
|
||||||
|
def test_free_threading(self):
|
||||||
|
"""Test for segfaults and aborts."""
|
||||||
|
|
||||||
|
def write(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
try: b.write(b'0' * randint(100, 1000))
|
||||||
|
except ValueError: pass # ignore write fail to closed file
|
||||||
|
|
||||||
|
def writelines(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.write(b'0\n' * randint(100, 1000))
|
||||||
|
|
||||||
|
def truncate(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
try: b.truncate(0)
|
||||||
|
except: BufferError # ignore exported buffer
|
||||||
|
|
||||||
|
def read(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.read()
|
||||||
|
|
||||||
|
def read1(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.read1()
|
||||||
|
|
||||||
|
def readline(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.readline()
|
||||||
|
|
||||||
|
def readlines(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.readlines()
|
||||||
|
|
||||||
|
def readinto(barrier, b, into, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.readinto(into)
|
||||||
|
|
||||||
|
def close(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.close()
|
||||||
|
|
||||||
|
def getvalue(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.getvalue()
|
||||||
|
|
||||||
|
def getbuffer(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.getbuffer()
|
||||||
|
|
||||||
|
def iter(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
list(b)
|
||||||
|
|
||||||
|
def getstate(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.__getstate__()
|
||||||
|
|
||||||
|
def setstate(barrier, b, st, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
b.__setstate__(st)
|
||||||
|
|
||||||
|
def sizeof(barrier, b, *ignore):
|
||||||
|
barrier.wait()
|
||||||
|
getsizeof(b)
|
||||||
|
|
||||||
|
self.check([write] * 10, BytesIO())
|
||||||
|
self.check([writelines] * 10, BytesIO())
|
||||||
|
self.check([write] * 10 + [truncate] * 10, BytesIO())
|
||||||
|
self.check([truncate] + [read] * 10, BytesIO(b'0\n'*204800))
|
||||||
|
self.check([truncate] + [read1] * 10, BytesIO(b'0\n'*204800))
|
||||||
|
self.check([truncate] + [readline] * 10, BytesIO(b'0\n'*20480))
|
||||||
|
self.check([truncate] + [readlines] * 10, BytesIO(b'0\n'*20480))
|
||||||
|
self.check([truncate] + [readinto] * 10, BytesIO(b'0\n'*204800), bytearray(b'0\n'*204800))
|
||||||
|
self.check([close] + [write] * 10, BytesIO())
|
||||||
|
self.check([truncate] + [getvalue] * 10, BytesIO(b'0\n'*204800))
|
||||||
|
self.check([truncate] + [getbuffer] * 10, BytesIO(b'0\n'*204800))
|
||||||
|
self.check([truncate] + [iter] * 10, BytesIO(b'0\n'*20480))
|
||||||
|
self.check([truncate] + [getstate] * 10, BytesIO(b'0\n'*204800))
|
||||||
|
self.check([truncate] + [setstate] * 10, BytesIO(b'0\n'*204800), (b'123', 0, None))
|
||||||
|
self.check([truncate] + [sizeof] * 10, BytesIO(b'0\n'*204800))
|
||||||
|
|
||||||
|
# no tests for seek or tell because they don't break anything
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Make :class:`io.BytesIO` safe in :term:`free-threaded <free threading>` build.
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION()
|
||||||
#include "pycore_object.h"
|
#include "pycore_object.h"
|
||||||
#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
|
#include "pycore_pyatomic_ft_wrappers.h"
|
||||||
|
#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
|
||||||
|
|
||||||
#include <stddef.h> // offsetof()
|
#include <stddef.h> // offsetof()
|
||||||
#include "_iomodule.h"
|
#include "_iomodule.h"
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
|
@ -50,7 +52,7 @@ check_closed(bytesio *self)
|
||||||
static int
|
static int
|
||||||
check_exports(bytesio *self)
|
check_exports(bytesio *self)
|
||||||
{
|
{
|
||||||
if (self->exports > 0) {
|
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
|
||||||
PyErr_SetString(PyExc_BufferError,
|
PyErr_SetString(PyExc_BufferError,
|
||||||
"Existing exports of data: object cannot be re-sized");
|
"Existing exports of data: object cannot be re-sized");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -68,15 +70,17 @@ check_exports(bytesio *self)
|
||||||
return NULL; \
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1)
|
#define SHARED_BUF(self) (!_PyObject_IsUniquelyReferenced((self)->buf))
|
||||||
|
|
||||||
|
|
||||||
/* Internal routine to get a line from the buffer of a BytesIO
|
/* Internal routine to get a line from the buffer of a BytesIO
|
||||||
object. Returns the length between the current position to the
|
object. Returns the length between the current position to the
|
||||||
next newline character. */
|
next newline character. */
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
scan_eol(bytesio *self, Py_ssize_t len)
|
scan_eol_lock_held(bytesio *self, Py_ssize_t len)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
|
||||||
|
|
||||||
const char *start, *n;
|
const char *start, *n;
|
||||||
Py_ssize_t maxlen;
|
Py_ssize_t maxlen;
|
||||||
|
|
||||||
|
|
@ -109,11 +113,13 @@ scan_eol(bytesio *self, Py_ssize_t len)
|
||||||
The caller should ensure that the 'size' argument is non-negative and
|
The caller should ensure that the 'size' argument is non-negative and
|
||||||
not lesser than self->string_size. Returns 0 on success, -1 otherwise. */
|
not lesser than self->string_size. Returns 0 on success, -1 otherwise. */
|
||||||
static int
|
static int
|
||||||
unshare_buffer(bytesio *self, size_t size)
|
unshare_buffer_lock_held(bytesio *self, size_t size)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
|
||||||
|
|
||||||
PyObject *new_buf;
|
PyObject *new_buf;
|
||||||
assert(SHARED_BUF(self));
|
assert(SHARED_BUF(self));
|
||||||
assert(self->exports == 0);
|
assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0);
|
||||||
assert(size >= (size_t)self->string_size);
|
assert(size >= (size_t)self->string_size);
|
||||||
new_buf = PyBytes_FromStringAndSize(NULL, size);
|
new_buf = PyBytes_FromStringAndSize(NULL, size);
|
||||||
if (new_buf == NULL)
|
if (new_buf == NULL)
|
||||||
|
|
@ -128,10 +134,12 @@ unshare_buffer(bytesio *self, size_t size)
|
||||||
The caller should ensure that the 'size' argument is non-negative. Returns
|
The caller should ensure that the 'size' argument is non-negative. Returns
|
||||||
0 on success, -1 otherwise. */
|
0 on success, -1 otherwise. */
|
||||||
static int
|
static int
|
||||||
resize_buffer(bytesio *self, size_t size)
|
resize_buffer_lock_held(bytesio *self, size_t size)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
|
||||||
|
|
||||||
assert(self->buf != NULL);
|
assert(self->buf != NULL);
|
||||||
assert(self->exports == 0);
|
assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0);
|
||||||
|
|
||||||
/* Here, unsigned types are used to avoid dealing with signed integer
|
/* Here, unsigned types are used to avoid dealing with signed integer
|
||||||
overflow, which is undefined in C. */
|
overflow, which is undefined in C. */
|
||||||
|
|
@ -160,7 +168,7 @@ resize_buffer(bytesio *self, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SHARED_BUF(self)) {
|
if (SHARED_BUF(self)) {
|
||||||
if (unshare_buffer(self, alloc) < 0)
|
if (unshare_buffer_lock_held(self, alloc) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -181,8 +189,10 @@ resize_buffer(bytesio *self, size_t size)
|
||||||
Inlining is disabled because it's significantly decreases performance
|
Inlining is disabled because it's significantly decreases performance
|
||||||
of writelines() in PGO build. */
|
of writelines() in PGO build. */
|
||||||
Py_NO_INLINE static Py_ssize_t
|
Py_NO_INLINE static Py_ssize_t
|
||||||
write_bytes(bytesio *self, PyObject *b)
|
write_bytes_lock_held(bytesio *self, PyObject *b)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
|
||||||
|
|
||||||
if (check_closed(self)) {
|
if (check_closed(self)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -202,13 +212,13 @@ write_bytes(bytesio *self, PyObject *b)
|
||||||
assert(self->pos >= 0);
|
assert(self->pos >= 0);
|
||||||
size_t endpos = (size_t)self->pos + len;
|
size_t endpos = (size_t)self->pos + len;
|
||||||
if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) {
|
if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) {
|
||||||
if (resize_buffer(self, endpos) < 0) {
|
if (resize_buffer_lock_held(self, endpos) < 0) {
|
||||||
len = -1;
|
len = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (SHARED_BUF(self)) {
|
else if (SHARED_BUF(self)) {
|
||||||
if (unshare_buffer(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) {
|
if (unshare_buffer_lock_held(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) {
|
||||||
len = -1;
|
len = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -245,13 +255,17 @@ write_bytes(bytesio *self, PyObject *b)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure))
|
bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure))
|
||||||
{
|
{
|
||||||
|
PyObject *ret;
|
||||||
bytesio *self = bytesio_CAST(op);
|
bytesio *self = bytesio_CAST(op);
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
if (self->buf == NULL) {
|
if (self->buf == NULL) {
|
||||||
Py_RETURN_TRUE;
|
ret = Py_True;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_RETURN_FALSE;
|
ret = Py_False;
|
||||||
}
|
}
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
|
@ -311,6 +325,7 @@ _io_BytesIO_flush_impl(bytesio *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.getbuffer
|
_io.BytesIO.getbuffer
|
||||||
|
|
||||||
cls: defining_class
|
cls: defining_class
|
||||||
|
|
@ -321,7 +336,7 @@ Get a read-write view over the contents of the BytesIO object.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls)
|
_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls)
|
||||||
/*[clinic end generated code: output=045091d7ce87fe4e input=0668fbb48f95dffa]*/
|
/*[clinic end generated code: output=045091d7ce87fe4e input=8295764061be77fd]*/
|
||||||
{
|
{
|
||||||
_PyIO_State *state = get_io_state_by_cls(cls);
|
_PyIO_State *state = get_io_state_by_cls(cls);
|
||||||
PyTypeObject *type = state->PyBytesIOBuffer_Type;
|
PyTypeObject *type = state->PyBytesIOBuffer_Type;
|
||||||
|
|
@ -340,6 +355,7 @@ _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.getvalue
|
_io.BytesIO.getvalue
|
||||||
|
|
||||||
Retrieve the entire contents of the BytesIO object.
|
Retrieve the entire contents of the BytesIO object.
|
||||||
|
|
@ -347,16 +363,16 @@ Retrieve the entire contents of the BytesIO object.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_getvalue_impl(bytesio *self)
|
_io_BytesIO_getvalue_impl(bytesio *self)
|
||||||
/*[clinic end generated code: output=b3f6a3233c8fd628 input=4b403ac0af3973ed]*/
|
/*[clinic end generated code: output=b3f6a3233c8fd628 input=c91bff398df0c352]*/
|
||||||
{
|
{
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
if (self->string_size <= 1 || self->exports > 0)
|
if (self->string_size <= 1 || FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0)
|
||||||
return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf),
|
return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf),
|
||||||
self->string_size);
|
self->string_size);
|
||||||
|
|
||||||
if (self->string_size != PyBytes_GET_SIZE(self->buf)) {
|
if (self->string_size != PyBytes_GET_SIZE(self->buf)) {
|
||||||
if (SHARED_BUF(self)) {
|
if (SHARED_BUF(self)) {
|
||||||
if (unshare_buffer(self, self->string_size) < 0)
|
if (unshare_buffer_lock_held(self, self->string_size) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -384,6 +400,7 @@ _io_BytesIO_isatty_impl(bytesio *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.tell
|
_io.BytesIO.tell
|
||||||
|
|
||||||
Current file position, an integer.
|
Current file position, an integer.
|
||||||
|
|
@ -391,22 +408,24 @@ Current file position, an integer.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_tell_impl(bytesio *self)
|
_io_BytesIO_tell_impl(bytesio *self)
|
||||||
/*[clinic end generated code: output=b54b0f93cd0e5e1d input=b106adf099cb3657]*/
|
/*[clinic end generated code: output=b54b0f93cd0e5e1d input=2c7b0e8f82e05c4d]*/
|
||||||
{
|
{
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
return PyLong_FromSsize_t(self->pos);
|
return PyLong_FromSsize_t(self->pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
read_bytes(bytesio *self, Py_ssize_t size)
|
read_bytes_lock_held(bytesio *self, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
|
||||||
|
|
||||||
const char *output;
|
const char *output;
|
||||||
|
|
||||||
assert(self->buf != NULL);
|
assert(self->buf != NULL);
|
||||||
assert(size <= self->string_size);
|
assert(size <= self->string_size);
|
||||||
if (size > 1 &&
|
if (size > 1 &&
|
||||||
self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
|
self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
|
||||||
self->exports == 0) {
|
FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
|
||||||
self->pos += size;
|
self->pos += size;
|
||||||
return Py_NewRef(self->buf);
|
return Py_NewRef(self->buf);
|
||||||
}
|
}
|
||||||
|
|
@ -417,6 +436,7 @@ read_bytes(bytesio *self, Py_ssize_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.read
|
_io.BytesIO.read
|
||||||
size: Py_ssize_t(accept={int, NoneType}) = -1
|
size: Py_ssize_t(accept={int, NoneType}) = -1
|
||||||
/
|
/
|
||||||
|
|
@ -429,7 +449,7 @@ Return an empty bytes object at EOF.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_read_impl(bytesio *self, Py_ssize_t size)
|
_io_BytesIO_read_impl(bytesio *self, Py_ssize_t size)
|
||||||
/*[clinic end generated code: output=9cc025f21c75bdd2 input=74344a39f431c3d7]*/
|
/*[clinic end generated code: output=9cc025f21c75bdd2 input=9e2f7ff3075fdd39]*/
|
||||||
{
|
{
|
||||||
Py_ssize_t n;
|
Py_ssize_t n;
|
||||||
|
|
||||||
|
|
@ -443,11 +463,12 @@ _io_BytesIO_read_impl(bytesio *self, Py_ssize_t size)
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return read_bytes(self, size);
|
return read_bytes_lock_held(self, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.read1
|
_io.BytesIO.read1
|
||||||
size: Py_ssize_t(accept={int, NoneType}) = -1
|
size: Py_ssize_t(accept={int, NoneType}) = -1
|
||||||
/
|
/
|
||||||
|
|
@ -460,12 +481,13 @@ Return an empty bytes object at EOF.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size)
|
_io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size)
|
||||||
/*[clinic end generated code: output=d0f843285aa95f1c input=440a395bf9129ef5]*/
|
/*[clinic end generated code: output=d0f843285aa95f1c input=a08fc9e507ab380c]*/
|
||||||
{
|
{
|
||||||
return _io_BytesIO_read_impl(self, size);
|
return _io_BytesIO_read_impl(self, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.readline
|
_io.BytesIO.readline
|
||||||
size: Py_ssize_t(accept={int, NoneType}) = -1
|
size: Py_ssize_t(accept={int, NoneType}) = -1
|
||||||
/
|
/
|
||||||
|
|
@ -479,18 +501,19 @@ Return an empty bytes object at EOF.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size)
|
_io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size)
|
||||||
/*[clinic end generated code: output=4bff3c251df8ffcd input=e7c3fbd1744e2783]*/
|
/*[clinic end generated code: output=4bff3c251df8ffcd input=db09d47e23cf2c9e]*/
|
||||||
{
|
{
|
||||||
Py_ssize_t n;
|
Py_ssize_t n;
|
||||||
|
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
|
|
||||||
n = scan_eol(self, size);
|
n = scan_eol_lock_held(self, size);
|
||||||
|
|
||||||
return read_bytes(self, n);
|
return read_bytes_lock_held(self, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.readlines
|
_io.BytesIO.readlines
|
||||||
size as arg: object = None
|
size as arg: object = None
|
||||||
/
|
/
|
||||||
|
|
@ -504,7 +527,7 @@ total number of bytes in the lines returned.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
|
_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
|
||||||
/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/
|
/*[clinic end generated code: output=09b8e34c880808ff input=5c57d7d78e409985]*/
|
||||||
{
|
{
|
||||||
Py_ssize_t maxsize, size, n;
|
Py_ssize_t maxsize, size, n;
|
||||||
PyObject *result, *line;
|
PyObject *result, *line;
|
||||||
|
|
@ -533,7 +556,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
output = PyBytes_AS_STRING(self->buf) + self->pos;
|
output = PyBytes_AS_STRING(self->buf) + self->pos;
|
||||||
while ((n = scan_eol(self, -1)) != 0) {
|
while ((n = scan_eol_lock_held(self, -1)) != 0) {
|
||||||
self->pos += n;
|
self->pos += n;
|
||||||
line = PyBytes_FromStringAndSize(output, n);
|
line = PyBytes_FromStringAndSize(output, n);
|
||||||
if (!line)
|
if (!line)
|
||||||
|
|
@ -556,6 +579,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.readinto
|
_io.BytesIO.readinto
|
||||||
buffer: Py_buffer(accept={rwbuffer})
|
buffer: Py_buffer(accept={rwbuffer})
|
||||||
/
|
/
|
||||||
|
|
@ -568,7 +592,7 @@ is set not to block and has no data to read.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
|
_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
|
||||||
/*[clinic end generated code: output=a5d407217dcf0639 input=1424d0fdce857919]*/
|
/*[clinic end generated code: output=a5d407217dcf0639 input=093a8d330de3fcd1]*/
|
||||||
{
|
{
|
||||||
Py_ssize_t len, n;
|
Py_ssize_t len, n;
|
||||||
|
|
||||||
|
|
@ -592,8 +616,9 @@ _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.truncate
|
_io.BytesIO.truncate
|
||||||
size: Py_ssize_t(accept={int, NoneType}, c_default="((bytesio *)self)->pos") = None
|
size: object = None
|
||||||
/
|
/
|
||||||
|
|
||||||
Truncate the file to at most size bytes.
|
Truncate the file to at most size bytes.
|
||||||
|
|
@ -603,44 +628,68 @@ The current file position is unchanged. Returns the new size.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size)
|
_io_BytesIO_truncate_impl(bytesio *self, PyObject *size)
|
||||||
/*[clinic end generated code: output=9ad17650c15fa09b input=dae4295e11c1bbb4]*/
|
/*[clinic end generated code: output=ab42491b4824f384 input=b4acb5f80481c053]*/
|
||||||
{
|
{
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
CHECK_EXPORTS(self);
|
CHECK_EXPORTS(self);
|
||||||
|
|
||||||
if (size < 0) {
|
Py_ssize_t new_size;
|
||||||
PyErr_Format(PyExc_ValueError,
|
|
||||||
"negative size value %zd", size);
|
if (size == Py_None) {
|
||||||
return NULL;
|
new_size = self->pos;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_size = PyLong_AsLong(size);
|
||||||
|
if (new_size == -1 && PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (new_size < 0) {
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"negative size value %zd", new_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < self->string_size) {
|
if (new_size < self->string_size) {
|
||||||
self->string_size = size;
|
self->string_size = new_size;
|
||||||
if (resize_buffer(self, size) < 0)
|
if (resize_buffer_lock_held(self, new_size) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PyLong_FromSsize_t(size);
|
return PyLong_FromSsize_t(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytesio_iternext(PyObject *op)
|
bytesio_iternext_lock_held(PyObject *op)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
|
||||||
|
|
||||||
Py_ssize_t n;
|
Py_ssize_t n;
|
||||||
bytesio *self = bytesio_CAST(op);
|
bytesio *self = bytesio_CAST(op);
|
||||||
|
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
|
|
||||||
n = scan_eol(self, -1);
|
n = scan_eol_lock_held(self, -1);
|
||||||
|
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return read_bytes(self, n);
|
return read_bytes_lock_held(self, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
bytesio_iternext(PyObject *op)
|
||||||
|
{
|
||||||
|
PyObject *ret;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(op);
|
||||||
|
ret = bytesio_iternext_lock_held(op);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.seek
|
_io.BytesIO.seek
|
||||||
pos: Py_ssize_t
|
pos: Py_ssize_t
|
||||||
whence: int = 0
|
whence: int = 0
|
||||||
|
|
@ -657,7 +706,7 @@ Returns the new absolute position.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
|
_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
|
||||||
/*[clinic end generated code: output=c26204a68e9190e4 input=1e875e6ebc652948]*/
|
/*[clinic end generated code: output=c26204a68e9190e4 input=20f05ddf659255df]*/
|
||||||
{
|
{
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
|
|
||||||
|
|
@ -700,6 +749,7 @@ _io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.write
|
_io.BytesIO.write
|
||||||
b: object
|
b: object
|
||||||
/
|
/
|
||||||
|
|
@ -711,13 +761,14 @@ Return the number of bytes written.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_write_impl(bytesio *self, PyObject *b)
|
_io_BytesIO_write_impl(bytesio *self, PyObject *b)
|
||||||
/*[clinic end generated code: output=d3e46bcec8d9e21c input=f5ec7c8c64ed720a]*/
|
/*[clinic end generated code: output=d3e46bcec8d9e21c input=46c0c17eac7474a4]*/
|
||||||
{
|
{
|
||||||
Py_ssize_t n = write_bytes(self, b);
|
Py_ssize_t n = write_bytes_lock_held(self, b);
|
||||||
return n >= 0 ? PyLong_FromSsize_t(n) : NULL;
|
return n >= 0 ? PyLong_FromSsize_t(n) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.writelines
|
_io.BytesIO.writelines
|
||||||
lines: object
|
lines: object
|
||||||
/
|
/
|
||||||
|
|
@ -731,7 +782,7 @@ each element.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
|
_io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
|
||||||
/*[clinic end generated code: output=03a43a75773bc397 input=e972539176fc8fc1]*/
|
/*[clinic end generated code: output=03a43a75773bc397 input=5d6a616ae39dc9ca]*/
|
||||||
{
|
{
|
||||||
PyObject *it, *item;
|
PyObject *it, *item;
|
||||||
|
|
||||||
|
|
@ -742,7 +793,7 @@ _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
while ((item = PyIter_Next(it)) != NULL) {
|
while ((item = PyIter_Next(it)) != NULL) {
|
||||||
Py_ssize_t ret = write_bytes(self, item);
|
Py_ssize_t ret = write_bytes_lock_held(self, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
|
|
@ -759,6 +810,7 @@ _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.close
|
_io.BytesIO.close
|
||||||
|
|
||||||
Disable all I/O operations.
|
Disable all I/O operations.
|
||||||
|
|
@ -766,7 +818,7 @@ Disable all I/O operations.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_close_impl(bytesio *self)
|
_io_BytesIO_close_impl(bytesio *self)
|
||||||
/*[clinic end generated code: output=1471bb9411af84a0 input=37e1f55556e61f60]*/
|
/*[clinic end generated code: output=1471bb9411af84a0 input=34ce76d8bd17a23b]*/
|
||||||
{
|
{
|
||||||
CHECK_EXPORTS(self);
|
CHECK_EXPORTS(self);
|
||||||
Py_CLEAR(self->buf);
|
Py_CLEAR(self->buf);
|
||||||
|
|
@ -788,35 +840,49 @@ _io_BytesIO_close_impl(bytesio *self)
|
||||||
function to use the efficient instance representation of PEP 307.
|
function to use the efficient instance representation of PEP 307.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy))
|
bytesio_getstate_lock_held(PyObject *op)
|
||||||
{
|
{
|
||||||
bytesio *self = bytesio_CAST(op);
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
|
||||||
PyObject *initvalue = _io_BytesIO_getvalue_impl(self);
|
|
||||||
PyObject *dict;
|
|
||||||
PyObject *state;
|
|
||||||
|
|
||||||
if (initvalue == NULL)
|
bytesio *self = bytesio_CAST(op);
|
||||||
return NULL;
|
PyObject *initvalue = _io_BytesIO_getvalue_impl(self);
|
||||||
if (self->dict == NULL) {
|
PyObject *dict;
|
||||||
dict = Py_NewRef(Py_None);
|
PyObject *state;
|
||||||
}
|
|
||||||
else {
|
|
||||||
dict = PyDict_Copy(self->dict);
|
|
||||||
if (dict == NULL) {
|
|
||||||
Py_DECREF(initvalue);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
|
if (initvalue == NULL)
|
||||||
Py_DECREF(initvalue);
|
return NULL;
|
||||||
return state;
|
if (self->dict == NULL) {
|
||||||
|
dict = Py_NewRef(Py_None);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dict = PyDict_Copy(self->dict);
|
||||||
|
if (dict == NULL) {
|
||||||
|
Py_DECREF(initvalue);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
|
||||||
|
Py_DECREF(initvalue);
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytesio_setstate(PyObject *op, PyObject *state)
|
bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy))
|
||||||
{
|
{
|
||||||
|
PyObject *ret;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(op);
|
||||||
|
ret = bytesio_getstate_lock_held(op);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
bytesio_setstate_lock_held(PyObject *op, PyObject *state)
|
||||||
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
|
||||||
|
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
PyObject *position_obj;
|
PyObject *position_obj;
|
||||||
PyObject *dict;
|
PyObject *dict;
|
||||||
|
|
@ -890,13 +956,23 @@ bytesio_setstate(PyObject *op, PyObject *state)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
bytesio_setstate(PyObject *op, PyObject *state)
|
||||||
|
{
|
||||||
|
PyObject *ret;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(op);
|
||||||
|
ret = bytesio_setstate_lock_held(op, state);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bytesio_dealloc(PyObject *op)
|
bytesio_dealloc(PyObject *op)
|
||||||
{
|
{
|
||||||
bytesio *self = bytesio_CAST(op);
|
bytesio *self = bytesio_CAST(op);
|
||||||
PyTypeObject *tp = Py_TYPE(self);
|
PyTypeObject *tp = Py_TYPE(self);
|
||||||
_PyObject_GC_UNTRACK(self);
|
_PyObject_GC_UNTRACK(self);
|
||||||
if (self->exports > 0) {
|
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
"deallocated BytesIO object has exported buffers");
|
"deallocated BytesIO object has exported buffers");
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
|
|
@ -932,6 +1008,7 @@ bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
_io.BytesIO.__init__
|
_io.BytesIO.__init__
|
||||||
initial_bytes as initvalue: object(c_default="NULL") = b''
|
initial_bytes as initvalue: object(c_default="NULL") = b''
|
||||||
|
|
||||||
|
|
@ -940,13 +1017,13 @@ Buffered I/O implementation using an in-memory bytes buffer.
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
|
_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
|
||||||
/*[clinic end generated code: output=65c0c51e24c5b621 input=aac7f31b67bf0fb6]*/
|
/*[clinic end generated code: output=65c0c51e24c5b621 input=3da5a74ee4c4f1ac]*/
|
||||||
{
|
{
|
||||||
/* In case, __init__ is called multiple times. */
|
/* In case, __init__ is called multiple times. */
|
||||||
self->string_size = 0;
|
self->string_size = 0;
|
||||||
self->pos = 0;
|
self->pos = 0;
|
||||||
|
|
||||||
if (self->exports > 0) {
|
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
|
||||||
PyErr_SetString(PyExc_BufferError,
|
PyErr_SetString(PyExc_BufferError,
|
||||||
"Existing exports of data: object cannot be re-sized");
|
"Existing exports of data: object cannot be re-sized");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -970,8 +1047,10 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
|
bytesio_sizeof_lock_held(PyObject *op)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
|
||||||
|
|
||||||
bytesio *self = bytesio_CAST(op);
|
bytesio *self = bytesio_CAST(op);
|
||||||
size_t res = _PyObject_SIZE(Py_TYPE(self));
|
size_t res = _PyObject_SIZE(Py_TYPE(self));
|
||||||
if (self->buf && !SHARED_BUF(self)) {
|
if (self->buf && !SHARED_BUF(self)) {
|
||||||
|
|
@ -984,6 +1063,16 @@ bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
|
||||||
return PyLong_FromSize_t(res);
|
return PyLong_FromSize_t(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
|
||||||
|
{
|
||||||
|
PyObject *ret;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(op);
|
||||||
|
ret = bytesio_sizeof_lock_held(op);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bytesio_traverse(PyObject *op, visitproc visit, void *arg)
|
bytesio_traverse(PyObject *op, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
|
|
@ -999,7 +1088,7 @@ bytesio_clear(PyObject *op)
|
||||||
{
|
{
|
||||||
bytesio *self = bytesio_CAST(op);
|
bytesio *self = bytesio_CAST(op);
|
||||||
Py_CLEAR(self->dict);
|
Py_CLEAR(self->dict);
|
||||||
if (self->exports == 0) {
|
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
|
||||||
Py_CLEAR(self->buf);
|
Py_CLEAR(self->buf);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1077,18 +1166,15 @@ PyType_Spec bytesio_spec = {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
|
bytesiobuf_getbuffer_lock_held(PyObject *op, Py_buffer *view, int flags)
|
||||||
{
|
{
|
||||||
bytesiobuf *obj = bytesiobuf_CAST(op);
|
bytesiobuf *obj = bytesiobuf_CAST(op);
|
||||||
bytesio *b = bytesio_CAST(obj->source);
|
bytesio *b = bytesio_CAST(obj->source);
|
||||||
|
|
||||||
if (view == NULL) {
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(b);
|
||||||
PyErr_SetString(PyExc_BufferError,
|
|
||||||
"bytesiobuf_getbuffer: view==NULL argument is obsolete");
|
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(b->exports) == 0 && SHARED_BUF(b)) {
|
||||||
return -1;
|
if (unshare_buffer_lock_held(b, b->string_size) < 0)
|
||||||
}
|
|
||||||
if (b->exports == 0 && SHARED_BUF(b)) {
|
|
||||||
if (unshare_buffer(b, b->string_size) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1096,16 +1182,32 @@ bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
|
||||||
(void)PyBuffer_FillInfo(view, op,
|
(void)PyBuffer_FillInfo(view, op,
|
||||||
PyBytes_AS_STRING(b->buf), b->string_size,
|
PyBytes_AS_STRING(b->buf), b->string_size,
|
||||||
0, flags);
|
0, flags);
|
||||||
b->exports++;
|
FT_ATOMIC_ADD_SSIZE(b->exports, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags)
|
||||||
|
{
|
||||||
|
if (view == NULL) {
|
||||||
|
PyErr_SetString(PyExc_BufferError,
|
||||||
|
"bytesiobuf_getbuffer: view==NULL argument is obsolete");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(bytesiobuf_CAST(op)->source);
|
||||||
|
ret = bytesiobuf_getbuffer_lock_held(op, view, flags);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bytesiobuf_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view))
|
bytesiobuf_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view))
|
||||||
{
|
{
|
||||||
bytesiobuf *obj = bytesiobuf_CAST(op);
|
bytesiobuf *obj = bytesiobuf_CAST(op);
|
||||||
bytesio *b = bytesio_CAST(obj->source);
|
bytesio *b = bytesio_CAST(obj->source);
|
||||||
b->exports--;
|
FT_ATOMIC_ADD_SSIZE(b->exports, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
||||||
66
Modules/_io/clinic/bytesio.c.h
generated
66
Modules/_io/clinic/bytesio.c.h
generated
|
|
@ -7,6 +7,7 @@ preserve
|
||||||
# include "pycore_runtime.h" // _Py_ID()
|
# include "pycore_runtime.h" // _Py_ID()
|
||||||
#endif
|
#endif
|
||||||
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
|
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
|
||||||
|
#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
|
||||||
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
|
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
|
||||||
|
|
||||||
PyDoc_STRVAR(_io_BytesIO_readable__doc__,
|
PyDoc_STRVAR(_io_BytesIO_readable__doc__,
|
||||||
|
|
@ -96,11 +97,18 @@ _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_getbuffer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
_io_BytesIO_getbuffer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
|
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
|
||||||
PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments");
|
PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments");
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
return _io_BytesIO_getbuffer_impl((bytesio *)self, cls);
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
|
return_value = _io_BytesIO_getbuffer_impl((bytesio *)self, cls);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_io_BytesIO_getvalue__doc__,
|
PyDoc_STRVAR(_io_BytesIO_getvalue__doc__,
|
||||||
|
|
@ -118,7 +126,13 @@ _io_BytesIO_getvalue_impl(bytesio *self);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored))
|
_io_BytesIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return _io_BytesIO_getvalue_impl((bytesio *)self);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
|
return_value = _io_BytesIO_getvalue_impl((bytesio *)self);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_io_BytesIO_isatty__doc__,
|
PyDoc_STRVAR(_io_BytesIO_isatty__doc__,
|
||||||
|
|
@ -156,7 +170,13 @@ _io_BytesIO_tell_impl(bytesio *self);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored))
|
_io_BytesIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return _io_BytesIO_tell_impl((bytesio *)self);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
|
return_value = _io_BytesIO_tell_impl((bytesio *)self);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_io_BytesIO_read__doc__,
|
PyDoc_STRVAR(_io_BytesIO_read__doc__,
|
||||||
|
|
@ -190,7 +210,9 @@ _io_BytesIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
skip_optional:
|
skip_optional:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_read_impl((bytesio *)self, size);
|
return_value = _io_BytesIO_read_impl((bytesio *)self, size);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
@ -227,7 +249,9 @@ _io_BytesIO_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
skip_optional:
|
skip_optional:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_read1_impl((bytesio *)self, size);
|
return_value = _io_BytesIO_read1_impl((bytesio *)self, size);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
@ -265,7 +289,9 @@ _io_BytesIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
skip_optional:
|
skip_optional:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_readline_impl((bytesio *)self, size);
|
return_value = _io_BytesIO_readline_impl((bytesio *)self, size);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
@ -301,7 +327,9 @@ _io_BytesIO_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
}
|
}
|
||||||
arg = args[0];
|
arg = args[0];
|
||||||
skip_optional:
|
skip_optional:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_readlines_impl((bytesio *)self, arg);
|
return_value = _io_BytesIO_readlines_impl((bytesio *)self, arg);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
@ -332,7 +360,9 @@ _io_BytesIO_readinto(PyObject *self, PyObject *arg)
|
||||||
_PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg);
|
_PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_readinto_impl((bytesio *)self, &buffer);
|
return_value = _io_BytesIO_readinto_impl((bytesio *)self, &buffer);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
/* Cleanup for buffer */
|
/* Cleanup for buffer */
|
||||||
|
|
@ -356,13 +386,13 @@ PyDoc_STRVAR(_io_BytesIO_truncate__doc__,
|
||||||
{"truncate", _PyCFunction_CAST(_io_BytesIO_truncate), METH_FASTCALL, _io_BytesIO_truncate__doc__},
|
{"truncate", _PyCFunction_CAST(_io_BytesIO_truncate), METH_FASTCALL, _io_BytesIO_truncate__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size);
|
_io_BytesIO_truncate_impl(bytesio *self, PyObject *size);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
_io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
Py_ssize_t size = ((bytesio *)self)->pos;
|
PyObject *size = Py_None;
|
||||||
|
|
||||||
if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) {
|
if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
@ -370,11 +400,11 @@ _io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
if (nargs < 1) {
|
if (nargs < 1) {
|
||||||
goto skip_optional;
|
goto skip_optional;
|
||||||
}
|
}
|
||||||
if (!_Py_convert_optional_to_ssize_t(args[0], &size)) {
|
size = args[0];
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
skip_optional:
|
skip_optional:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_truncate_impl((bytesio *)self, size);
|
return_value = _io_BytesIO_truncate_impl((bytesio *)self, size);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
@ -428,7 +458,9 @@ _io_BytesIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
skip_optional:
|
skip_optional:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_seek_impl((bytesio *)self, pos, whence);
|
return_value = _io_BytesIO_seek_impl((bytesio *)self, pos, whence);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
@ -453,7 +485,9 @@ _io_BytesIO_write(PyObject *self, PyObject *b)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_write_impl((bytesio *)self, b);
|
return_value = _io_BytesIO_write_impl((bytesio *)self, b);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
@ -479,7 +513,9 @@ _io_BytesIO_writelines(PyObject *self, PyObject *lines)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO_writelines_impl((bytesio *)self, lines);
|
return_value = _io_BytesIO_writelines_impl((bytesio *)self, lines);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
@ -499,7 +535,13 @@ _io_BytesIO_close_impl(bytesio *self);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored))
|
_io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return _io_BytesIO_close_impl((bytesio *)self);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
|
return_value = _io_BytesIO_close_impl((bytesio *)self);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_io_BytesIO___init____doc__,
|
PyDoc_STRVAR(_io_BytesIO___init____doc__,
|
||||||
|
|
@ -558,9 +600,11 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
}
|
}
|
||||||
initvalue = fastargs[0];
|
initvalue = fastargs[0];
|
||||||
skip_optional_pos:
|
skip_optional_pos:
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue);
|
return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=6dbfd82f4e9d4ef3 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=580205daa01def2e input=a9049054013a1b77]*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue