Skip to content

Commit 83578dc

Browse files
authored
PYTHON-2334: Fix gevent.Timeout race condition (#472)
If gevent raises a Timeout during self.lock acquisition, a _socket_semaphore count will be lost. Using "with" will release the condition even on exception being raised.
1 parent ff327b3 commit 83578dc

File tree

2 files changed

+24
-20
lines changed

2 files changed

+24
-20
lines changed

pymongo/pool.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -1257,12 +1257,15 @@ def _get_socket(self, all_credentials):
12571257
if not self._socket_semaphore.acquire(
12581258
True, self.opts.wait_queue_timeout):
12591259
self._raise_wait_queue_timeout()
1260-
with self.lock:
1261-
self.active_sockets += 1
12621260

12631261
# We've now acquired the semaphore and must release it on error.
12641262
sock_info = None
1263+
incremented = False
12651264
try:
1265+
with self.lock:
1266+
self.active_sockets += 1
1267+
incremented = True
1268+
12661269
while sock_info is None:
12671270
try:
12681271
with self.lock:
@@ -1279,8 +1282,10 @@ def _get_socket(self, all_credentials):
12791282
# We checked out a socket but authentication failed.
12801283
sock_info.close_socket(ConnectionClosedReason.ERROR)
12811284
self._socket_semaphore.release()
1282-
with self.lock:
1283-
self.active_sockets -= 1
1285+
1286+
if incremented:
1287+
with self.lock:
1288+
self.active_sockets -= 1
12841289

12851290
if self.enabled_for_cmap:
12861291
self.opts.event_listeners.publish_connection_check_out_failed(

pymongo/thread_util.py

+15-16
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,21 @@ def acquire(self, blocking=True, timeout=None):
4040
raise ValueError("can't specify timeout for non-blocking acquire")
4141
rc = False
4242
endtime = None
43-
self._cond.acquire()
44-
while self._value == 0:
45-
if not blocking:
46-
break
47-
if timeout is not None:
48-
if endtime is None:
49-
endtime = _time() + timeout
50-
else:
51-
timeout = endtime - _time()
52-
if timeout <= 0:
53-
break
54-
self._cond.wait(timeout)
55-
else:
56-
self._value = self._value - 1
57-
rc = True
58-
self._cond.release()
43+
with self._cond:
44+
while self._value == 0:
45+
if not blocking:
46+
break
47+
if timeout is not None:
48+
if endtime is None:
49+
endtime = _time() + timeout
50+
else:
51+
timeout = endtime - _time()
52+
if timeout <= 0:
53+
break
54+
self._cond.wait(timeout)
55+
else:
56+
self._value = self._value - 1
57+
rc = True
5958
return rc
6059

6160
__enter__ = acquire

0 commit comments

Comments
 (0)