Skip to content

Commit 6ce10f4

Browse files
authored
Change ThreadLock to ThreadRLock to resolve rare deadlock
1 parent 38f277c commit 6ce10f4

File tree

2 files changed

+8
-7
lines changed

2 files changed

+8
-7
lines changed

httpcore/_sync/connection_pool.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .._backends.base import SOCKET_OPTION, NetworkBackend
1010
from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol
1111
from .._models import Origin, Proxy, Request, Response
12-
from .._synchronization import Event, ShieldCancellation, ThreadLock
12+
from .._synchronization import Event, ShieldCancellation, ThreadRLock
1313
from .connection import HTTPConnection
1414
from .interfaces import ConnectionInterface, RequestInterface
1515

@@ -123,7 +123,7 @@ def __init__(
123123
# We only mutate the state of the connection pool within an 'optional_thread_lock'
124124
# context. This holds a threading lock unless we're running in async mode,
125125
# in which case it is a no-op.
126-
self._optional_thread_lock = ThreadLock()
126+
self._optional_thread_lock = ThreadRLock()
127127

128128
def create_connection(self, origin: Origin) -> ConnectionInterface:
129129
if self._proxy is not None:

httpcore/_synchronization.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class AsyncThreadLock:
9494
"""
9595
This is a threading-only lock for no-I/O contexts.
9696
97-
In the sync case `ThreadLock` provides thread locking.
97+
In the sync case `ThreadRLock` provides thread locking.
9898
In the async case `AsyncThreadLock` is a no-op.
9999
"""
100100

@@ -253,18 +253,19 @@ def __exit__(
253253
self._lock.release()
254254

255255

256-
class ThreadLock:
256+
class ThreadRLock:
257257
"""
258258
This is a threading-only lock for no-I/O contexts.
259+
The lock type is a reentrant lock.
259260
260-
In the sync case `ThreadLock` provides thread locking.
261+
In the sync case `ThreadRLock` provides thread locking.
261262
In the async case `AsyncThreadLock` is a no-op.
262263
"""
263264

264265
def __init__(self) -> None:
265-
self._lock = threading.Lock()
266+
self._lock = threading.RLock()
266267

267-
def __enter__(self) -> ThreadLock:
268+
def __enter__(self) -> ThreadRLock:
268269
self._lock.acquire()
269270
return self
270271

0 commit comments

Comments
 (0)