forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-119247: Add macros to use PySequence_Fast safely in free-thr…
…eaded build (python#119315) Add `Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST` and `Py_END_CRITICAL_SECTION_SEQUENCE_FAST` macros and update `str.join` to use them. Also add a regression test that would crash reliably without this patch.
- Loading branch information
1 parent
2b3fb76
commit baf347d
Showing
4 changed files
with
106 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import sys | ||
import unittest | ||
|
||
from itertools import cycle | ||
from threading import Event, Thread | ||
from unittest import TestCase | ||
|
||
from test.support import threading_helper | ||
|
||
@threading_helper.requires_working_threading() | ||
class TestStr(TestCase): | ||
def test_racing_join_extend(self): | ||
'''Test joining a string being extended by another thread''' | ||
l = [] | ||
ITERS = 100 | ||
READERS = 10 | ||
done_event = Event() | ||
def writer_func(): | ||
for i in range(ITERS): | ||
l.extend(map(str, range(i))) | ||
l.clear() | ||
done_event.set() | ||
def reader_func(): | ||
while not done_event.is_set(): | ||
''.join(l) | ||
writer = Thread(target=writer_func) | ||
readers = [] | ||
for x in range(READERS): | ||
reader = Thread(target=reader_func) | ||
readers.append(reader) | ||
reader.start() | ||
|
||
writer.start() | ||
writer.join() | ||
for reader in readers: | ||
reader.join() | ||
|
||
def test_racing_join_replace(self): | ||
''' | ||
Test joining a string of characters being replaced with ephemeral | ||
strings by another thread. | ||
''' | ||
l = [*'abcdefg'] | ||
MAX_ORDINAL = 1_000 | ||
READERS = 10 | ||
done_event = Event() | ||
|
||
def writer_func(): | ||
for i, c in zip(cycle(range(len(l))), | ||
map(chr, range(128, MAX_ORDINAL))): | ||
l[i] = c | ||
done_event.set() | ||
|
||
def reader_func(): | ||
while not done_event.is_set(): | ||
''.join(l) | ||
''.join(l) | ||
''.join(l) | ||
''.join(l) | ||
|
||
writer = Thread(target=writer_func) | ||
readers = [] | ||
for x in range(READERS): | ||
reader = Thread(target=reader_func) | ||
readers.append(reader) | ||
reader.start() | ||
|
||
writer.start() | ||
writer.join() | ||
for reader in readers: | ||
reader.join() | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
4 changes: 4 additions & 0 deletions
4
Misc/NEWS.d/next/C API/2024-05-21-11-35-11.gh-issue-119247.U6n6mh.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Added ``Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST`` and | ||
``Py_END_CRITICAL_SECTION_SEQUENCE_FAST`` macros to make it possible to use | ||
PySequence_Fast APIs safely when free-threaded, and update str.join to work | ||
without the GIL using them. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters