• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aio-libs / multidict / 34609305018
87%

Build:
DEFAULT BRANCH: master
Ran 11 Sep 2026 02:19PM UTC
Jobs 1
Files 31
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

11 Sep 2026 02:18PM UTC coverage: 85.387% (+0.1%) from 85.251%
34609305018

push

github

web-flow
Protect MultiDict single-item ops and view set-algebra with a critical section (#1438)

<!-- Thank you for your contribution! -->

## What do these changes do?

Extends the free-threaded-build locking from #1431/#1433 to the
operations
that were still running without holding `self`'s lock at all: `add()`,
`__setitem__`/`__delitem__`, `get()`/`getone()`/`__getitem__`,
`__contains__`,
`getall()`, `setdefault()`, `pop()`/`popone()`/`popall()`/`popitem()`,
`__eq__`, iteration (`keys()`/`items()`/`values()`), and the
`&`/`|`/`-`/`^`/`in`/`isdisjoint()` operations on `.keys()` and
`.items()`
views. A resize triggered by one thread's mutation could free the hash
table while a concurrent, unprotected reader on another thread was still
walking it.

The view set-algebra methods (`itemsview`/`keysview` `and`/`or`/`sub`/
`contains`/`isdisjoint`) use the same `_lock_held`-style split CPython's
own `dictobject.c` uses: the existing body is extracted into a `_impl`
function, and a thin wrapper acquires the critical section around it,
since several of these have multiple `goto`/return exits that can't be
wrapped with `Py_BEGIN_CRITICAL_SECTION`/`Py_END_CRITICAL_SECTION` in
place.

This also fixes a compile error in the in-progress atomic-reads branch
this stacks on: `htkeys.h` referenced `atomic_load_ssize_relaxed()`
without including the header where it's defined. That header (renamed
`atomic_helpers.h`) now selects its atomic-load backend the same way
CPython's `Include/cpython/pyatomic.h` does: GCC/Clang builtins by
default, C11 `stdatomic.h` next, and MSVC intrinsics only as the last
resort for `cl.exe`, which supports neither.

`len()` stays lock-free (a relaxed atomic read of `md->used`), matching
CPython's own `dict_length()`, which is also unlocked even though the
rest of `dictobject.c` is fully critical-section-protected.

Lock-free reads are intentionally out of scope here. CPython's dict
gets its `get()`/`__contains__`/iteration speed back with a separate,... (continued)

642 of 1284 branches covered (50.0%)

Branch coverage included in aggregate %.

74 of 74 new or added lines in 1 file covered. (100.0%)

4430 of 4656 relevant lines covered (95.15%)

1.9 hits per line

Jobs
ID Job ID Ran Files Coverage
1 MyPy - 34609305018.1 11 Sep 2026 02:19PM UTC 62
85.39
GitHub Action Run
Source Files on build 34609305018
  • Tree
  • List 31
  • Changed 2
  • Source Changed 1
  • Coverage Changed 2
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #34609305018
  • 0f8797fd on github
  • Prev Build on master (#34588321475)
  • Next Build on master (#34609726091)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc