mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
lan: don't make room while holding the address map
make_room logs turned-away connections, and the log reads by_address: count called it with that lock held, so the accept loop deadlocked the first time the server filled with a log writer set. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
21249821f2
commit
dd4b209ae7
1 file changed
+11
-6
@@ -728,14 +728,19 @@ impl Shared {
|
||||
/// most and no connection that waits could be closed to make room ([`Shared::make_room`]).
|
||||
fn count(self: &Arc<Self>, ip: IpAddr) -> Option<Counted> {
|
||||
let most = self.max_players().saturating_add(SPARE_CONNECTIONS);
|
||||
let mut by = self.by_address.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let here = by.get(&ip).copied().unwrap_or(0);
|
||||
if here >= PER_ADDRESS && !shared_address(ip)
|
||||
|| self.connections.load(Ordering::Acquire) >= most && !self.make_room()
|
||||
{
|
||||
let here = |by: &HashMap<IpAddr, usize>| by.get(&ip).copied().unwrap_or(0);
|
||||
let by = self.by_address.lock().unwrap_or_else(|e| e.into_inner());
|
||||
if here(&by) >= PER_ADDRESS && !shared_address(ip) {
|
||||
return None;
|
||||
}
|
||||
by.insert(ip, here + 1);
|
||||
// make_room logs, which reads by_address: never call it holding that lock.
|
||||
drop(by);
|
||||
if self.connections.load(Ordering::Acquire) >= most && !self.make_room() {
|
||||
return None;
|
||||
}
|
||||
let mut by = self.by_address.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let n = here(&by) + 1;
|
||||
by.insert(ip, n);
|
||||
self.connections.fetch_add(1, Ordering::AcqRel);
|
||||
let id = self.next_connection.fetch_add(1, Ordering::Relaxed);
|
||||
Some(Counted(self.clone(), ip, id))
|
||||
|
||||
Reference in new issue
Block a user