Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/library/email.parser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ message body, instead setting the payload to the raw body.

Read all the data from the binary file-like object *fp*, parse the
resulting bytes, and return the message object. *fp* must support
both the :meth:`~io.IOBase.readline` and the :meth:`~io.IOBase.read`
both the :meth:`~io.IOBase.readline` and the :meth:`~io.BufferedIOBase.read`
methods.

The bytes contained in *fp* must be formatted as a block of :rfc:`5322`
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ The following exceptions are the exceptions that are usually raised.
.. exception:: EOFError

Raised when the :func:`input` function hits an end-of-file condition (EOF)
without reading any data. (Note: the :meth:`!io.IOBase.read` and
without reading any data. (Note: the :meth:`io.TextIOBase.read` and
:meth:`io.IOBase.readline` methods return an empty string when they hit EOF.)


Expand Down
10 changes: 5 additions & 5 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1294,8 +1294,8 @@ as internal buffering of data.

This function is intended for low-level I/O. For normal usage, use the
built-in function :func:`open`, which returns a :term:`file object` with
:meth:`~file.read` and :meth:`~file.write` methods (and many more). To
wrap a file descriptor in a file object, use :func:`fdopen`.
:meth:`~io.BufferedIOBase.read` and :meth:`~io.BufferedIOBase.write` methods.
To wrap a file descriptor in a file object, use :func:`fdopen`.

.. versionchanged:: 3.3
Added the *dir_fd* parameter.
Expand Down Expand Up @@ -1670,7 +1670,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
descriptor as returned by :func:`os.open` or :func:`pipe`. To read a
"file object" returned by the built-in function :func:`open` or by
:func:`popen` or :func:`fdopen`, or :data:`sys.stdin`, use its
:meth:`~file.read` or :meth:`~file.readline` methods.
:meth:`~io.TextIOBase.read` or :meth:`~io.IOBase.readline` methods.

.. versionchanged:: 3.5
If the system call is interrupted and the signal handler does not raise an
Expand Down Expand Up @@ -1905,7 +1905,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
descriptor as returned by :func:`os.open` or :func:`pipe`. To write a "file
object" returned by the built-in function :func:`open` or by :func:`popen` or
:func:`fdopen`, or :data:`sys.stdout` or :data:`sys.stderr`, use its
:meth:`~file.write` method.
:meth:`~io.TextIOBase.write` method.

.. versionchanged:: 3.5
If the system call is interrupted and the signal handler does not raise an
Expand Down Expand Up @@ -4720,7 +4720,7 @@ to be ignored.
The current process is replaced immediately. Open file objects and
descriptors are not flushed, so if there may be data buffered
on these open files, you should flush them using
:func:`sys.stdout.flush` or :func:`os.fsync` before calling an
:func:`~io.IOBase.flush` or :func:`os.fsync` before calling an
:func:`exec\* <execl>` function.

The "l" and "v" variants of the :func:`exec\* <execl>` functions differ in how
Expand Down
16 changes: 16 additions & 0 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1401,12 +1401,28 @@ also :func:`os.popen`, :func:`os.fdopen`, and the
:meth:`~socket.socket.makefile` method of socket objects (and perhaps by
other functions or methods provided by extension modules).

File objects implement common methods, listed below, to simplify usage in
generic code. They are expected to be :ref:`context-managers`.

The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are
initialized to file objects corresponding to the interpreter's standard
input, output and error streams; they are all open in text mode and
therefore follow the interface defined by the :class:`io.TextIOBase`
abstract class.

.. method:: file.read(size=-1, /)

Retrieve up to *size* data from the file. As a convenience if *size* is
unspecified or -1 retrieve all data available.

.. method:: file.write(data, /)

Store *data* to the file.

.. method:: file.close()

Flush any buffers and close the underlying file.


Internal types
--------------
Expand Down
7 changes: 7 additions & 0 deletions Include/internal/pycore_stackref.h
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,13 @@ _PyThreadState_PushCStackRef(PyThreadState *tstate, _PyCStackRef *ref)
ref->ref = PyStackRef_NULL;
}

static inline void
_PyThreadState_PushCStackRefNew(PyThreadState *tstate, _PyCStackRef *ref, PyObject *obj)
{
_PyThreadState_PushCStackRef(tstate, ref);
ref->ref = PyStackRef_FromPyObjectNew(obj);
}

static inline void
_PyThreadState_PopCStackRef(PyThreadState *tstate, _PyCStackRef *ref)
{
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2908,6 +2908,22 @@ def check(funcs, it):
check([iter_next] + [iter_reduce] * 10, iter(ba)) # for tsan
check([iter_next] + [iter_setstate] * 10, iter(ba)) # for tsan

@unittest.skipUnless(support.Py_GIL_DISABLED, 'this test can only possibly fail with GIL disabled')
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_free_threading_bytearray_resize(self):
def resize_stress(ba):
for _ in range(1000):
try:
ba.resize(1000)
ba.resize(1)
except (BufferError, ValueError):
pass

ba = bytearray(100)
threads = [threading.Thread(target=resize_stress, args=(ba,)) for _ in range(4)]
with threading_helper.start_threads(threads):
pass

if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Make :meth:`bytearray.resize` thread-safe in the free-threaded build by
using a critical section and calling the lock-held variant of the resize
function.
5 changes: 3 additions & 2 deletions Objects/bytearrayobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,7 @@ bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix)


/*[clinic input]
@critical_section
bytearray.resize
size: Py_ssize_t
New size to resize to.
Expand All @@ -1515,10 +1516,10 @@ Resize the internal buffer of bytearray to len.

static PyObject *
bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size)
/*[clinic end generated code: output=f73524922990b2d9 input=6c9a260ca7f72071]*/
/*[clinic end generated code: output=f73524922990b2d9 input=116046316a2b5cfc]*/
{
Py_ssize_t start_size = PyByteArray_GET_SIZE(self);
int result = PyByteArray_Resize((PyObject *)self, size);
int result = bytearray_resize_lock_held((PyObject *)self, size);
if (result < 0) {
return NULL;
}
Expand Down
4 changes: 3 additions & 1 deletion Objects/clinic/bytearrayobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 9 additions & 11 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -12360,18 +12360,16 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *
PyObject *mro, *res;
Py_ssize_t i, n;

BEGIN_TYPE_LOCK();
mro = lookup_tp_mro(su_obj_type);
/* keep a strong reference to mro because su_obj_type->tp_mro can be
replaced during PyDict_GetItemRef(dict, name, &res) and because
another thread can modify it after we end the critical section
below */
Py_XINCREF(mro);
END_TYPE_LOCK();

if (mro == NULL)
return NULL;

/* Keep a strong reference to mro because su_obj_type->tp_mro can be
replaced during PyDict_GetItemRef(dict, name, &res). */
PyThreadState *tstate = _PyThreadState_GET();
_PyCStackRef mro_ref;
_PyThreadState_PushCStackRefNew(tstate, &mro_ref, mro);

assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);

Expand All @@ -12382,7 +12380,7 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *
}
i++; /* skip su->type (if any) */
if (i >= n) {
Py_DECREF(mro);
_PyThreadState_PopCStackRef(tstate, &mro_ref);
return NULL;
}

Expand All @@ -12393,13 +12391,13 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *

if (PyDict_GetItemRef(dict, name, &res) != 0) {
// found or error
Py_DECREF(mro);
_PyThreadState_PopCStackRef(tstate, &mro_ref);
return res;
}

i++;
} while (i < n);
Py_DECREF(mro);
_PyThreadState_PopCStackRef(tstate, &mro_ref);
return NULL;
}

Expand Down
16 changes: 16 additions & 0 deletions Tools/ftscalingbench/ftscalingbench.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,22 @@ def instantiate_typing_namedtuple():
for _ in range(1000 * WORK_SCALE):
obj = MyTypingNamedTuple(x=1, y=2, z=3)

@register_benchmark
def super_call():
# TODO: super() on the same class from multiple threads still doesn't
# scale well, so use a class per-thread here for now.
class Base:
def method(self):
return 1

class Derived(Base):
def method(self):
return super().method()

obj = Derived()
for _ in range(1000 * WORK_SCALE):
obj.method()


@register_benchmark
def deepcopy():
Expand Down
Loading