Skip to content

Commit 311337f

Browse files
committed
potentially fixed deadlock in deregister_session_stream, buy not overlapping locks and using an upgradable lock on handshakes/sessions.
1 parent dc2f2a8 commit 311337f

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

crates/net/network-devp2p/src/session_container.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{collections::BTreeMap, sync::Arc, time::Duration};
66

77
use crate::{io::*, node_table::*, session::Session};
88
use network::{Error, ErrorKind, NetworkIoMessage, PeerId};
9-
use parking_lot::{Mutex, RwLock, RwLockReadGuard};
9+
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard};
1010

1111
pub type SharedSession = Arc<Mutex<Session>>;
1212

@@ -25,8 +25,8 @@ pub struct SessionContainer {
2525
last_handshake: usize,
2626
// the handshake cursor is a improvement to find new available handshake slots. it defines the next starting search position.
2727
current_handshake_cursor: Mutex<usize>,
28-
sessions: Arc<RwLock<std::collections::BTreeMap<usize, SharedSession>>>,
29-
handshakes: Arc<RwLock<std::collections::BTreeMap<usize, SharedSession>>>, // Separate map for handshakes
28+
sessions: RwLock<std::collections::BTreeMap<usize, SharedSession>>,
29+
handshakes: RwLock<std::collections::BTreeMap<usize, SharedSession>>, // Separate map for handshakes
3030
// for egress handshakes, we know the Node ID we want to do a handshake with, so we can do efficient lookups.
3131
handshakes_egress_map: RwLock<BTreeMap<ethereum_types::H512, usize>>,
3232
node_id_to_session: Mutex<LruCache<ethereum_types::H512, usize>>, // used to map Node IDs to last used session tokens.
@@ -41,8 +41,8 @@ impl SessionContainer {
4141
max_handshakes: usize,
4242
) -> Self {
4343
SessionContainer {
44-
sessions: Arc::new(RwLock::new(std::collections::BTreeMap::new())),
45-
handshakes: Arc::new(RwLock::new(std::collections::BTreeMap::new())),
44+
sessions: RwLock::new(std::collections::BTreeMap::new()),
45+
handshakes: RwLock::new(std::collections::BTreeMap::new()),
4646
handshakes_egress_map: RwLock::new(BTreeMap::new()),
4747
current_handshake_cursor: Mutex::new(first_handshake_token),
4848
first_handshake: first_handshake_token,
@@ -433,12 +433,13 @@ impl SessionContainer {
433433
pub(crate) fn deregister_session_stream<Host: mio::deprecated::Handler>(
434434
&self,
435435
stream: usize,
436+
436437
event_loop: &mut mio::deprecated::EventLoop<Host>,
437438
) {
438-
let mut connections = if stream < self.last_handshake {
439-
self.handshakes.write()
439+
let connections = if stream < self.last_handshake {
440+
self.handshakes.upgradable_read()
440441
} else {
441-
self.sessions.write()
442+
self.sessions.upgradable_read()
442443
};
443444

444445
if let Some(connection) = connections.get(&stream).cloned() {
@@ -447,8 +448,15 @@ impl SessionContainer {
447448
// make sure it is the same connection that the event was generated for
448449
c.deregister_socket(event_loop)
449450
.expect("Error deregistering socket");
450-
connections.remove(&stream);
451+
drop(c);
452+
let mut connections_write = RwLockUpgradableReadGuard::upgrade(connections);
453+
connections_write.remove(&stream);
454+
//RwLockUpgradableReadGuard::<'_, parking_lot::RawRwLock, BTreeMap<usize, Arc<parking_lot::lock_api::Mutex<parking_lot::RawMutex, Session>>>>::upgrade(connections).remove(&stream);
455+
} else {
456+
debug!(target: "network", "Tried to deregister session stream {} but it is not expired.", stream);
451457
}
458+
} else {
459+
debug!(target: "network", "Tried to deregister session stream {} but it does not exist.", stream);
452460
}
453461
}
454462

0 commit comments

Comments
 (0)