Skip to content

Commit 2e4179b

Browse files
committed
8325179: Race in BasicDirectoryModel.validateFileCache
8238169: BasicDirectoryModel getDirectories and DoChangeContents.run can deadlock Backport-of: e66788c16563d343f6cccd2807a251ccc6f9b64a
1 parent f08e5e8 commit 2e4179b

File tree

1 file changed

+48
-52
lines changed

1 file changed

+48
-52
lines changed

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java

Lines changed: 48 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,13 @@ public void propertyChange(PropertyChangeEvent e) {
9898
* This method is used to interrupt file loading thread.
9999
*/
100100
public void invalidateFileCache() {
101-
if (filesLoader != null) {
102-
filesLoader.loadThread.interrupt();
103-
filesLoader.cancelRunnables();
104-
filesLoader = null;
101+
synchronized (this) {
102+
if (filesLoader != null) {
103+
filesLoader.loadThread.interrupt();
104+
filesLoader = null;
105+
// Increment fetch ID to invalidate pending DoChangeContents
106+
fetchID.incrementAndGet();
107+
}
105108
}
106109
}
107110

@@ -156,14 +159,15 @@ public void validateFileCache() {
156159
if (currentDirectory == null) {
157160
return;
158161
}
159-
if (filesLoader != null) {
160-
filesLoader.loadThread.interrupt();
161-
filesLoader.cancelRunnables();
162-
}
162+
synchronized (this) {
163+
if (filesLoader != null) {
164+
filesLoader.loadThread.interrupt();
165+
}
163166

164-
int fid = fetchID.incrementAndGet();
165-
setBusy(true, fid);
166-
filesLoader = new FilesLoader(currentDirectory, fid);
167+
int fid = fetchID.incrementAndGet();
168+
setBusy(true, fid);
169+
filesLoader = new FilesLoader(currentDirectory, fid);
170+
}
167171
}
168172

169173
/**
@@ -270,7 +274,6 @@ private final class FilesLoader implements Runnable {
270274
private final boolean fileSelectionEnabled;
271275
private final int fid;
272276
private final File currentDirectory;
273-
private volatile DoChangeContents runnable;
274277
private final Thread loadThread;
275278

276279
private FilesLoader(File currentDirectory, int fid) {
@@ -291,22 +294,20 @@ public void run() {
291294
}
292295

293296
private void run0() {
294-
FileSystemView fileSystem = fileSystemView;
295-
296297
if (loadThread.isInterrupted()) {
297298
return;
298299
}
299300

300-
File[] list = fileSystem.getFiles(currentDirectory, useFileHiding);
301+
File[] list = fileSystemView.getFiles(currentDirectory, useFileHiding);
301302

302303
if (loadThread.isInterrupted()) {
303304
return;
304305
}
305306

306307
final Vector<File> newFileCache = new Vector<File>();
307-
Vector<File> newFiles = new Vector<File>();
308+
final Vector<File> newFiles = new Vector<File>();
308309

309-
// run through the file list, add directories and selectable files to fileCache
310+
// Run through the file list, add directories and selectable files to fileCache
310311
// Note that this block must be OUTSIDE of Invoker thread because of
311312
// deadlock possibility with custom synchronized FileSystemView
312313
for (File file : list) {
@@ -333,7 +334,7 @@ private void run0() {
333334

334335
// To avoid loads of synchronizations with Invoker and improve performance we
335336
// execute the whole block on the COM thread
336-
runnable = ShellFolder.invoke(new Callable<DoChangeContents>() {
337+
DoChangeContents runnable = ShellFolder.invoke(new Callable<DoChangeContents>() {
337338
public DoChangeContents call() {
338339
synchronized (fileCache) {
339340
int newSize = newFileCache.size();
@@ -389,7 +390,7 @@ public DoChangeContents call() {
389390
}
390391
if (!fileCache.equals(newFileCache)) {
391392
if (loadThread.isInterrupted()) {
392-
cancelRunnables();
393+
return null;
393394
}
394395
return new DoChangeContents(newFileCache, 0, fileCache, 0, fid);
395396
}
@@ -402,12 +403,6 @@ public DoChangeContents call() {
402403
SwingUtilities.invokeLater(runnable);
403404
}
404405
}
405-
406-
private void cancelRunnables() {
407-
if (runnable != null) {
408-
runnable.cancel();
409-
}
410-
}
411406
}
412407

413408

@@ -516,45 +511,46 @@ public void run() {
516511
private final class DoChangeContents implements Runnable {
517512
private final List<File> addFiles;
518513
private final List<File> remFiles;
519-
private boolean doFire = true;
520514
private final int fid;
521-
private int addStart = 0;
522-
private int remStart = 0;
515+
private final int addStart;
516+
private final int remStart;
523517

524-
DoChangeContents(List<File> addFiles, int addStart, List<File> remFiles,
525-
int remStart, int fid) {
518+
private DoChangeContents(List<File> addFiles, int addStart,
519+
List<File> remFiles, int remStart,
520+
int fid) {
526521
this.addFiles = addFiles;
527522
this.addStart = addStart;
528523
this.remFiles = remFiles;
529524
this.remStart = remStart;
530525
this.fid = fid;
531526
}
532527

533-
synchronized void cancel() {
534-
doFire = false;
535-
}
528+
@Override
529+
public void run() {
530+
if (fetchID.get() != fid) {
531+
return;
532+
}
536533

537-
public synchronized void run() {
538-
if (fetchID.get() == fid && doFire) {
539-
int remSize = (remFiles == null) ? 0 : remFiles.size();
540-
int addSize = (addFiles == null) ? 0 : addFiles.size();
541-
synchronized(fileCache) {
542-
if (remSize > 0) {
543-
fileCache.removeAll(remFiles);
544-
}
545-
if (addSize > 0) {
546-
fileCache.addAll(addStart, addFiles);
547-
}
548-
files = null;
549-
directories = null;
534+
final int remSize = (remFiles == null) ? 0 : remFiles.size();
535+
final int addSize = (addFiles == null) ? 0 : addFiles.size();
536+
final int cacheSize;
537+
synchronized (fileCache) {
538+
if (remSize > 0) {
539+
fileCache.removeAll(remFiles);
550540
}
551-
if (remSize > 0 && addSize == 0) {
552-
fireIntervalRemoved(BasicDirectoryModel.this, remStart, remStart + remSize - 1);
553-
} else if (addSize > 0 && remSize == 0 && addStart + addSize <= fileCache.size()) {
554-
fireIntervalAdded(BasicDirectoryModel.this, addStart, addStart + addSize - 1);
555-
} else {
556-
fireContentsChanged();
541+
if (addSize > 0) {
542+
fileCache.addAll(addStart, addFiles);
557543
}
544+
files = null;
545+
directories = null;
546+
cacheSize = fileCache.size();
547+
}
548+
if (remSize > 0 && addSize == 0) {
549+
fireIntervalRemoved(BasicDirectoryModel.this, remStart, remStart + remSize - 1);
550+
} else if (addSize > 0 && remSize == 0 && addStart + addSize <= cacheSize) {
551+
fireIntervalAdded(BasicDirectoryModel.this, addStart, addStart + addSize - 1);
552+
} else {
553+
fireContentsChanged();
558554
}
559555
}
560556
}

0 commit comments

Comments
 (0)