diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 3e766b5f7f..7a4e2bc7b0 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -741,6 +741,7 @@ public class PeerCoordinator implements PeerListener _log.debug("Updated piece priorities called but no priorities to set?"); return; } + List toCancel = new ArrayList(); synchronized(wantedPieces) { // Add incomplete and previously unwanted pieces to the list // Temp to avoid O(n**2) @@ -775,23 +776,31 @@ public class PeerCoordinator implements PeerListener p.setPriority(priority); } else { iter.remove(); - // cancel all peers - for (Peer peer : peers) { - peer.cancel(p.getId()); - } + toCancel.add(p); } } if (_log.shouldLog(Log.DEBUG)) _log.debug("Updated piece priorities, now wanted: " + wantedPieces); // if we added pieces, they will be in-order unless we shuffle Collections.shuffle(wantedPieces, _random); + } - // update request queues, in case we added wanted pieces - // and we were previously uninterested - for (Peer peer : peers) { - peer.request(); + // cancel outside of wantedPieces lock to avoid deadlocks + if (!toCancel.isEmpty()) { + // cancel all peers + for (Peer peer : peers) { + for (Piece p : toCancel) { + peer.cancel(p.getId()); + } } } + + // ditto, avoid deadlocks + // update request queues, in case we added wanted pieces + // and we were previously uninterested + for (Peer peer : peers) { + peer.request(); + } } /** diff --git a/history.txt b/history.txt index a29368b6cb..0f0e252024 100644 --- a/history.txt +++ b/history.txt @@ -2,6 +2,7 @@ * i2psnark: - Refactor tracker map - Prevent torrent shutdown when changing file priority to skip + - Fix deadlock when changing file priorities * RoutingKeyModifier: Update after large clock shift 2012-05-20 zzz