Skip to content

Commit 4ba1d84

Browse files
committed
Fix IDE hang when projects with different "Process files asynchronously" are open
Fixes #160 This problem only happens when at least 2 projects with different "Process files asynchronously" are open and a save is executed. If a save (Ctrl + S) is performed it saves both projects in parallel, causing a lock failure as one project locks the UI while the other one (which has the lock / runs async) tries to acquire the UI thread, thus causing a deadlock.
1 parent f71a6ad commit 4ba1d84

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

src/main/java/software/xdev/saveactions/core/service/impl/AbstractSaveActionsService.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77

88
import java.util.ArrayList;
99
import java.util.Arrays;
10+
import java.util.Collections;
1011
import java.util.List;
1112
import java.util.Map;
1213
import java.util.Objects;
1314
import java.util.Optional;
1415
import java.util.Set;
16+
import java.util.WeakHashMap;
1517
import java.util.concurrent.locks.ReentrantLock;
1618
import java.util.stream.Stream;
1719

@@ -59,7 +61,8 @@ abstract class AbstractSaveActionsService implements SaveActionsService
5961
private final boolean javaAvailable;
6062
private final boolean compilingAvailable;
6163

62-
private final ReentrantLock guardedProcessPsiFilesLock = new ReentrantLock();
64+
private final Map<Project, ReentrantLock> guardedProcessPsiFilesLocks =
65+
Collections.synchronizedMap(new WeakHashMap<>());
6366

6467
protected AbstractSaveActionsService(final StorageFactory storageFactory)
6568
{
@@ -100,20 +103,31 @@ public void guardedProcessPsiFiles(
100103
@Override
101104
public void run(@NotNull final ProgressIndicator indicator)
102105
{
103-
AbstractSaveActionsService.this.processPsiFilesIfNecessaryWithLock(engine, indicator);
106+
AbstractSaveActionsService.this.processPsiFilesIfNecessaryWithLock(project, engine, indicator);
104107
}
105108
}.queue();
106109
return;
107110
}
108111

109-
this.processPsiFilesIfNecessaryWithLock(engine, null);
112+
this.processPsiFilesIfNecessaryWithLock(project, engine, null);
110113
}
111114

112-
private void processPsiFilesIfNecessaryWithLock(final Engine engine, final ProgressIndicator indicator)
115+
private void processPsiFilesIfNecessaryWithLock(
116+
final Project project,
117+
final Engine engine,
118+
final ProgressIndicator indicator)
113119
{
114-
LOGGER.trace("Getting lock");
115-
this.guardedProcessPsiFilesLock.lock();
116-
LOGGER.trace("Got lock");
120+
if(LOGGER.isTraceEnabled())
121+
{
122+
LOGGER.trace("Getting lock - " + project.getName());
123+
}
124+
final ReentrantLock lock =
125+
this.guardedProcessPsiFilesLocks.computeIfAbsent(project, ignored -> new ReentrantLock());
126+
lock.lock();
127+
if(LOGGER.isTraceEnabled())
128+
{
129+
LOGGER.trace("Got lock - " + project.getName());
130+
}
117131
try
118132
{
119133
engine.processPsiFilesIfNecessary(
@@ -122,8 +136,11 @@ private void processPsiFilesIfNecessaryWithLock(final Engine engine, final Progr
122136
}
123137
finally
124138
{
125-
this.guardedProcessPsiFilesLock.unlock();
126-
LOGGER.trace("Released lock");
139+
lock.unlock();
140+
if(LOGGER.isTraceEnabled())
141+
{
142+
LOGGER.trace("Released lock - " + project.getName());
143+
}
127144
}
128145
}
129146

0 commit comments

Comments
 (0)