Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3c0be9c
Add librt.threading.Lock
JukkaL Mar 14, 2026
e94b365
Add test
JukkaL Mar 14, 2026
36e91e1
Add tests
JukkaL Mar 14, 2026
5cb9aa2
Add macOS support
JukkaL Mar 14, 2026
420ca6b
Add generic pthread implementation
JukkaL Mar 14, 2026
e17290b
Support Windows (untested)
JukkaL Mar 14, 2026
4c864b9
Add some primitives
JukkaL Mar 14, 2026
e33bd42
Optimize 'with' statement
JukkaL Mar 14, 2026
cc874e0
Use pthread on Linux
JukkaL Mar 19, 2026
b9d2e95
Use pthreads on macOS
JukkaL Mar 19, 2026
5382468
Lint
JukkaL Mar 19, 2026
9a230a1
Optimize
JukkaL Mar 19, 2026
4ee0f71
WIP benchmark
JukkaL Mar 19, 2026
8c54de5
Fix double init
JukkaL Mar 23, 2026
d5c4306
Support keyword argument
JukkaL Mar 23, 2026
ce9b478
Use the more recent approach for defining librt submodules
JukkaL Apr 27, 2026
030d09b
Use Python 3.14 PyMutex on 3.14+
JukkaL Apr 27, 2026
585ef10
Misc updates
JukkaL Apr 27, 2026
00811f5
Revert "WIP benchmark"
JukkaL Jun 1, 2026
7a4e707
Allow release from a different thread on posix
JukkaL Jun 2, 2026
5ce8750
Add sem_t implementation
JukkaL Jun 2, 2026
dca25a4
Allow Lock to be released on different thread in Windows
JukkaL Jun 3, 2026
002b31d
Reapply "WIP benchmark"
JukkaL Jun 3, 2026
ef35856
Drop unncessary _Atomic in pthread back end
JukkaL Jun 3, 2026
d66b7cf
Avoid atomic ops when using sem_t back end (breaks 3.13t!)
JukkaL Jun 3, 2026
0bd5fee
Use PyMutex on 3.13 as well
JukkaL Jun 3, 2026
713c5e7
Fix race condition
JukkaL Jun 3, 2026
8976171
No longer support 3.13, and with non-blocking lock on 3.14
JukkaL Jun 3, 2026
f0c34e6
Handle signals on 3.14
JukkaL Jun 3, 2026
77cb9a4
Fix 3.13t builds by using posix implementation
JukkaL Jun 3, 2026
8022967
Make lock acquire interruptible
JukkaL Jun 3, 2026
2902b29
Fix error detection
JukkaL Jun 3, 2026
ba0a692
Fix signal behavior when using pthread backend
JukkaL Jun 3, 2026
c0d9211
Add tests
JukkaL Jun 3, 2026
1279f44
Update comment
JukkaL Jun 3, 2026
7a00ff1
Use sem_t backend on 3.14 + Linux + GIL, as it's faster
JukkaL Jun 3, 2026
eb92e21
WIP EXPERIMENT
JukkaL Jun 3, 2026
4ae93d4
Faster PyMutex implementation (semantic deviation from CPython)
JukkaL Jun 3, 2026
042d770
Use PyMutex always on 3.14+
JukkaL Jun 17, 2026
8ba5e62
Remove benchmark
JukkaL Jul 7, 2026
f6901bb
Remove the experimental gating
JukkaL Jul 7, 2026
556b06f
Update some comments
JukkaL Jul 7, 2026
da92768
Update mypyc/lib-rt/threading/librt_threading.c
JukkaL Jul 7, 2026
717c79d
Update mypyc/lib-rt/threading/librt_threading.c
JukkaL Jul 7, 2026
badfb11
Address feedback
JukkaL Jul 7, 2026
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
16 changes: 16 additions & 0 deletions mypy/typeshed/stubs/librt/librt/threading.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from types import TracebackType
from typing import final

@final
class Lock:
def acquire(self, blocking: bool = True) -> bool: ...
def release(self) -> None: ...
def locked(self) -> bool: ...
def __enter__(self) -> bool: ...
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
/,
) -> None: ...
6 changes: 6 additions & 0 deletions mypyc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ class ModDesc(NamedTuple):
),
ModDesc("librt.time", ["time/librt_time.c"], ["time/librt_time.h"], []),
ModDesc("librt.random", ["random/librt_random.c"], ["random/librt_random.h"], ["random"]),
ModDesc(
"librt.threading",
["threading/librt_threading.c"],
["threading/librt_threading.h"],
["threading"],
),
]

try:
Expand Down
5 changes: 5 additions & 0 deletions mypyc/codegen/emitmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
LIBRT_BASE64,
LIBRT_RANDOM,
LIBRT_STRINGS,
LIBRT_THREADING,
LIBRT_TIME,
LIBRT_VECS,
Capsule,
Expand Down Expand Up @@ -1261,6 +1262,10 @@ def emit_module_exec_func(
emitter.emit_line("if (import_librt_time() < 0) {")
emitter.emit_line("return -1;")
emitter.emit_line("}")
if LIBRT_THREADING in module.dependencies:
emitter.emit_line("if (import_librt_threading() < 0) {")
emitter.emit_line("return -1;")
emitter.emit_line("}")
if LIBRT_VECS in module.dependencies:
emitter.emit_line("if (import_librt_vecs() < 0) {")
emitter.emit_line("return -1;")
Expand Down
1 change: 1 addition & 0 deletions mypyc/ir/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def get_header(self) -> str:
LIBRT_VECS: Final = Capsule("librt.vecs")
LIBRT_TIME: Final = Capsule("librt.time")
LIBRT_RANDOM: Final = Capsule("librt.random")
LIBRT_THREADING: Final = Capsule("librt.threading")

BYTES_EXTRA_OPS: Final = SourceDep("bytes_extra_ops.c")
BYTES_WRITER_EXTRA_OPS: Final = SourceDep("byteswriter_extra_ops.c")
Expand Down
11 changes: 9 additions & 2 deletions mypyc/ir/rtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class to enable the new behavior. In rare cases, adding a new
from typing import TYPE_CHECKING, ClassVar, Final, Generic, TypeGuard, TypeVar, Union, final

from mypyc.common import HAVE_IMMORTAL, IS_32_BIT_PLATFORM, PLATFORM_SIZE, JsonDict, short_name
from mypyc.ir.deps import LIBRT_RANDOM, LIBRT_STRINGS, LIBRT_VECS, Dependency
from mypyc.ir.deps import LIBRT_RANDOM, LIBRT_STRINGS, LIBRT_THREADING, LIBRT_VECS, Dependency
from mypyc.namegen import NameGenerator

if TYPE_CHECKING:
Expand Down Expand Up @@ -550,12 +550,19 @@ def __hash__(self) -> int:
} | {
"librt.random.Random": RPrimitive(
"librt.random.Random", is_unboxed=False, is_refcounted=True, dependencies=(LIBRT_RANDOM,)
)
),
"librt.threading.Lock": RPrimitive(
"librt.threading.Lock",
is_unboxed=False,
is_refcounted=True,
dependencies=(LIBRT_THREADING,),
),
}

bytes_writer_rprimitive: Final = KNOWN_NATIVE_TYPES["librt.strings.BytesWriter"]
string_writer_rprimitive: Final = KNOWN_NATIVE_TYPES["librt.strings.StringWriter"]
random_rprimitive: Final = KNOWN_NATIVE_TYPES["librt.random.Random"]
lock_rprimitive: Final = KNOWN_NATIVE_TYPES["librt.threading.Lock"]


def is_native_rprimitive(rtype: RType) -> bool:
Expand Down
32 changes: 32 additions & 0 deletions mypyc/irbuild/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
c_pyssize_t_rprimitive,
exc_rtuple,
is_tagged,
lock_rprimitive,
none_rprimitive,
object_pointer_rprimitive,
object_rprimitive,
Expand Down Expand Up @@ -115,6 +116,7 @@
restore_exc_info_op,
)
from mypyc.primitives.generic_ops import iter_op, next_raw_op, py_delattr_op
from mypyc.primitives.librt_threading_ops import lock_acquire_op, lock_release_op
from mypyc.primitives.misc_ops import (
check_stop_op,
coro_op,
Expand Down Expand Up @@ -1108,6 +1110,10 @@ def transform_with(
al = "a" if is_async else ""

mgr_v = builder.accept(expr)

if not is_async and mgr_v.type == lock_rprimitive:
transform_with_lock(builder, mgr_v, target, body, line)
return
is_native = isinstance(mgr_v.type, RInstance)
if is_native:
value = builder.add(MethodCall(mgr_v, f"__{al}enter__", args=[], line=line))
Expand Down Expand Up @@ -1179,6 +1185,32 @@ def finally_body() -> None:
)


def transform_with_lock(
builder: IRBuilder, mgr_v: Value, target: Lvalue | None, body: GenFunc, line: int
) -> None:
"""Optimized 'with' for librt.threading.Lock.

Generate a simple try/finally with direct acquire/release calls.
Lock.__exit__ never suppresses exceptions, so we don't need the
full PEP 343 try/except/finally machinery.
"""
# __enter__: acquire the lock
value = builder.primitive_op(lock_acquire_op, [mgr_v], line)

mgr = builder.maybe_spill(mgr_v)

def try_body() -> None:
if target:
builder.assign(builder.get_assignment_target(target), value, line)
body()

def finally_body() -> None:
# __exit__: release the lock (ignoring exception info)
builder.primitive_op(lock_release_op, [builder.read(mgr, line)], line)

transform_try_finally_stmt(builder, try_body, finally_body, line)


def transform_with_stmt(builder: IRBuilder, o: WithStmt) -> None:
# Generate separate logic for each expr in it, left to right
def generate(i: int) -> None:
Expand Down
6 changes: 6 additions & 0 deletions mypyc/lib-rt/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,5 +164,11 @@ def run(self) -> None:
include_dirs=["."],
extra_compile_args=cflags,
),
Extension(
"librt.threading",
["threading/librt_threading.c"],
include_dirs=[".", "threading"],
extra_compile_args=cflags,
),
]
)
Loading
Loading