Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-128942: make arraymodule.c free-thread safe (lock-free)#130771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
tom-pytel wants to merge43 commits intopython:main
base:main
Choose a base branch
Loading
fromtom-pytel:fix-issue-128942-lockfree
Open
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
43 commits
Select commitHold shift + click to select a range
f54c5fc
slow arraymodule
tom-pytelMar 1, 2025
4c71f00
lockfree read and write single element
tom-pytelMar 2, 2025
512c4c7
📜🤖 Added by blurb_it.
blurb-it[bot]Mar 2, 2025
060100f
ensure_shared_on_resize() in one more place
tom-pytelMar 2, 2025
d0b17c6
fix stupid direct return out of critical section
tom-pytelMar 3, 2025
c17b787
requested changes
tom-pytelMar 3, 2025
4fd8383
downgrade to _Py_atomic_load_ptr_relaxed in missed place
tom-pytelMar 3, 2025
d00f2b7
arraymodule linked statically
tom-pytelMar 4, 2025
a3e6004
cleanups
tom-pytelMar 5, 2025
fb6212a
test and tsan stuff
tom-pytelMar 5, 2025
04a8f9d
getters and setters using atomics
tom-pytelMar 5, 2025
01423fd
fix 2 byte wchar_t
tom-pytelMar 6, 2025
99331dd
remove debug printf
tom-pytelMar 6, 2025
07c98cc
just a hunch...
tom-pytelMar 6, 2025
cf3bbbb
atomic "memcpy"
tom-pytelMar 6, 2025
51135a4
misc
tom-pytelMar 7, 2025
fff827e
use proper type FT_ macros
tom-pytelMar 8, 2025
12f0ff6
atomic aggregate _Py_atomic_source_memcpy_relaxed()
tom-pytelMar 10, 2025
1a6b8df
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 11, 2025
94ef417
remove atomic memcpy
tom-pytelMar 11, 2025
0056412
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 11, 2025
1431784
regen clinic
tom-pytelMar 11, 2025
460d3d7
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 11, 2025
409239c
requested changes
tom-pytelMar 15, 2025
a6f17c9
more requested changes
tom-pytelMar 17, 2025
b5d219e
__declspec(align(8)) for Windows
tom-pytelMar 17, 2025
2c82071
shut up check-c-globals
tom-pytelMar 17, 2025
1ba50e9
alignment changes
tom-pytelMar 20, 2025
576aebf
MS_WINDOWS -> _MSC_VER
tom-pytelMar 20, 2025
4dd0954
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 20, 2025
d4e5313
#include "pycore_gc.h", something moved
tom-pytelMar 20, 2025
48eabe3
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 25, 2025
c056b13
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 25, 2025
affae8e
remove NULL check in arraydata_free()
tom-pytelMar 25, 2025
689c7a3
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMar 31, 2025
3e2f8cd
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelApr 4, 2025
7286fed
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelApr 14, 2025
6550906
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelApr 23, 2025
5b35203
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMay 2, 2025
15d92ca
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMay 5, 2025
2e7132e
change to use new _Py_ALIGN_AS() macro
tom-pytelMay 5, 2025
06f86cf
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMay 8, 2025
d29c208
Merge branch 'main' into fix-issue-128942-lockfree
tom-pytelMay 23, 2025
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
NextNext commit
slow arraymodule
  • Loading branch information
@tom-pytel
tom-pytel committedMar 1, 2025
commitf54c5fc6c0394ea322d82aed3e338544251ec7f9
265 changes: 265 additions & 0 deletionsLib/test/test_array.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,16 +3,20 @@
"""

import collections.abc
import io
import unittest
from test import support
from test.support import import_helper
from test.support import os_helper
from test.support import threading_helper
from test.support import _2G
import weakref
import pickle
import operator
import random
import struct
import sys
import threading
import warnings

import array
Expand DownExpand Up@@ -1673,5 +1677,266 @@ def test_gh_128961(self):
self.assertRaises(StopIteration, next, it)


class FreeThreadingTest(unittest.TestCase):
# Test pretty much everything that can break under free-threading.
# Non-deterministic, but at least one of these things will fail if
# array module is not free-thread safe.

@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(self):
def pop1(b, a): # MODIFIES!
b.wait()
try: a.pop()
except IndexError: pass

def append1(b, a): # MODIFIES!
b.wait()
a.append(2)

def insert1(b, a): # MODIFIES!
b.wait()
a.insert(0, 2)

def extend(b, a): # MODIFIES!
c = array.array('i', [2])
b.wait()
a.extend(c)

def extend2(b, a, c): # MODIFIES!
b.wait()
a.extend(c)

def inplace_concat(b, a): # MODIFIES!
c = array.array('i', [2])
b.wait()
a += c

def inplace_concat2(b, a, c): # MODIFIES!
b.wait()
a += c

def inplace_repeat2(b, a): # MODIFIES!
b.wait()
a *= 2

def clear(b, a, *args): # MODIFIES!
b.wait()
a.clear()

def clear2(b, a, c): # MODIFIES c!
b.wait()
try: c.clear()
except BufferError: pass

def remove1(b, a): # MODIFIES!
b.wait()
try: a.remove(1)
except ValueError: pass

def fromunicode(b, a): # MODIFIES!
b.wait()
a.fromunicode('test')

def frombytes(b, a): # MODIFIES!
b.wait()
a.frombytes(b'0000')

def frombytes2(b, a, c): # MODIFIES!
b.wait()
a.frombytes(c)

def fromlist(b, a): # MODIFIES!
n = random.randint(0, 100)
b.wait()
a.fromlist([2] * n)

def ass_subscr2(b, a, c): # MODIFIES!
b.wait()
a[:] = c

def ass0(b, a): # modifies inplace
b.wait()
try: a[0] = 0
except IndexError: pass

def byteswap(b, a): # modifies inplace
b.wait()
a.byteswap()

def tounicode(b, a):
b.wait()
a.tounicode()

def tobytes(b, a):
b.wait()
a.tobytes()

def tolist(b, a):
b.wait()
a.tolist()

def tofile(b, a):
f = io.BytesIO()
b.wait()
a.tofile(f)

def reduce_ex2(b, a):
b.wait()
a.__reduce_ex__(2)

def reduce_ex3(b, a):
b.wait()
c = a.__reduce_ex__(3)
assert not c[1] or 0xdd not in c[1][3]

def copy(b, a):
b.wait()
c = a.__copy__()
assert not c or 0xdd not in c

def repr1(b, a):
b.wait()
repr(a)

def repeat2(b, a):
b.wait()
a * 2

def count1(b, a):
b.wait()
a.count(1)

def index1(b, a):
b.wait()
try: a.index(1)
except ValueError: pass

def contains1(b, a):
b.wait()
try: 1 in a
except ValueError: pass

def subscr0(b, a):
b.wait()
try: a[0]
except IndexError: pass

def concat(b, a):
b.wait()
a + a

def concat2(b, a, c):
b.wait()
a + c

def richcmplhs(b, a):
c = a[:]
b.wait()
a == c

def richcmprhs(b, a):
c = a[:]
b.wait()
c == a

def new(b, a):
tc = a.typecode
b.wait()
array.array(tc, a)

def repr_(b, a):
b.wait()
repr(a)

def irepeat(b, a): # MODIFIES!
b.wait()
a *= 2

def newi(b, l):
b.wait()
array.array('i', l)

def fromlistl(b, a, l): # MODIFIES!
b.wait()
a.fromlist(l)

def fromlistlclear(b, a, l): # MODIFIES LIST!
b.wait()
l.clear()

def iter_next(b, a, it): # MODIFIES ITERATOR!
b.wait()
list(it)

def iter_reduce(b, a, it):
b.wait()
c = it.__reduce__()
assert not c[1] or 0xdd not in c[1][0]

def check(funcs, a=None, *args):
if a is None:
a = array.array('i', [1])

barrier = threading.Barrier(len(funcs))
threads = []

for func in funcs:
thread = threading.Thread(target=func, args=(barrier, a, *args))

threads.append(thread)

with threading_helper.start_threads(threads):
pass

check([pop1] * 10)
check([pop1] + [subscr0] * 10)
check([append1] * 10)
check([insert1] * 10)
check([pop1] + [index1] * 10)
check([pop1] + [contains1] * 10)
check([insert1] + [repeat2] * 10)
check([pop1] + [repr1] * 10)
check([inplace_repeat2] * 10)
check([byteswap] * 10)
check([insert1] + [clear] * 10)
check([pop1] + [count1] * 10)
check([remove1] * 10)
check([clear] + [copy] * 10, array.array('B', b'0' * 0x400000))
check([pop1] + [reduce_ex2] * 10)
check([clear] + [reduce_ex3] * 10, array.array('B', b'0' * 0x400000))
check([pop1] + [tobytes] * 10)
check([pop1] + [tolist] * 10)
check([clear, tounicode] * 10, array.array('w', 'a'*10000))
check([clear, tofile] * 10, array.array('w', 'a'*10000))
check([clear] + [extend] * 10)
check([clear] + [inplace_concat] * 10)
check([clear] + [concat] * 10, array.array('w', 'a'*10000))
check([fromunicode] * 10, array.array('w', 'a'))
check([frombytes] * 10)
check([fromlist] * 10)
check([clear] + [richcmplhs] * 10, array.array('i', [1]*10000))
check([clear] + [richcmprhs] * 10, array.array('i', [1]*10000))
check([clear, ass0] * 10, array.array('i', [1]*10000)) # to test array_ass_item must disable Py_mp_ass_subscript
check([clear] + [new] * 10, array.array('w', 'a'*10000))
check([clear] + [repr_] * 10, array.array('B', b'0' * 0x40000))
check([clear] + [repr_] * 10, array.array('B', b'0' * 0x40000))
check([clear] + [irepeat] * 10, array.array('B', b'0' * 0x40000))
check([clear] + [iter_reduce] * 10, a := array.array('B', b'0' * 0x400), iter(a))

# make sure we handle non-self objects correctly
check([clear] + [newi] * 10, [2] * random.randint(0, 100))
check([fromlistlclear] + [fromlistl] * 10, array.array('i', [1]), [2] * random.randint(0, 100))
check([clear2] + [concat2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000))
check([clear2] + [inplace_concat2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000))
check([clear2] + [extend2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000))
check([clear2] + [ass_subscr2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000))
check([clear2] + [frombytes2] * 10, array.array('w', 'a'*10000), array.array('B', b'a'*10000))

# iterator stuff
check([clear] + [iter_next] * 10, a := array.array('i', [1] * 10), iter(a))


if __name__ == "__main__":
unittest.main()
Loading

[8]ページ先頭

©2009-2025 Movatter.jp