Skip to content

Conversation

@drmoose
Copy link
Contributor

@drmoose drmoose commented Nov 4, 2025

Using tcpq:// for LCM communication, the initial lcm_create call attempts to do network IO, including a recv to get the version string from its remote server. This may block indefinitely (or at least until TCP times out), so we should release the GIL while it's happening.

Originally discovered by @Pluviolithic, who was seeing background threads hanging on epoll until LCM's recv finished. He supplied this script that reproduces the error by trying to talk to itself:

import selectors
import socket
import threading
import time

import lcm

select = selectors.DefaultSelector()


def connect_lcm() -> None:
    time.sleep(5)
    lcm.LCM("tcpq://127.0.0.1:8675")


def accept(_server_socket: socket.socket, _mask: int) -> None:
    print("Accepted...")


select = selectors.DefaultSelector()

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1", 8675))

server_socket.listen(5)
server_socket.setblocking(False)  # noqa: FBT003

select.register(server_socket, selectors.EVENT_READ, accept)

threading.Thread(target=connect_lcm).start()

while True:
    print("selecting...")
    select.select(1)
    print("done selecting...")

The initial lcm_create call attempts to do network IO, including a recv to get the version string from its remote server. This may block indefinitely (or at least until TCP times out), so we should release the GIL while it's happening.

Originally reported on a private channel by @Pluviolithic, who was seeing background threads hanging on epoll until LCM's recv finished.
@nosracd nosracd merged commit c752203 into lcm-proj:master Nov 4, 2025
68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants