diff --git a/test/build.xml b/test/build.xml index 1036f8f05f5de6be99ef9455073b9480bea1fc80..67ff69ddcb8dce1966dab6b7955cb2ce1ed7e79e 100644 --- a/test/build.xml +++ b/test/build.xml @@ -14,6 +14,7 @@ <path refid='util-classes'/> </classpath> <test name='net.sf.briar.FileReadWriteTest'/> + <test name='net.sf.briar.LockFairnessTest'/> <test name='net.sf.briar.crypto.CounterModeTest'/> <test name='net.sf.briar.db.BasicH2Test'/> <test name='net.sf.briar.db.DatabaseCleanerImplTest'/> diff --git a/test/net/sf/briar/LockFairnessTest.java b/test/net/sf/briar/LockFairnessTest.java new file mode 100644 index 0000000000000000000000000000000000000000..57a6daed16f93ab107cbd9df41379298a25ac4f2 --- /dev/null +++ b/test/net/sf/briar/LockFairnessTest.java @@ -0,0 +1,81 @@ +package net.sf.briar; + +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import junit.framework.TestCase; + +import org.junit.Test; + +public class LockFairnessTest extends TestCase { + + @Test + public void testWritersDoNotStarevWithFairLocks() throws Exception { + // Create a fair fair read-write lock + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + // Create a ton of reader threads that repeatedly acquire the read lock, + // sleep for a few ms and release the lock + Thread[] readers = new Thread[20]; + for(int i = 0; i < readers.length; i++) { + readers[i] = new ReaderThread(lock); + } + // Stagger the start times of the readers so they release the read lock + // at different times + for(int i = 0; i < readers.length; i++) { + readers[i].start(); + Thread.sleep(7); + } + // Create a writer thread, which should be able to acquire the lock + WriterThread writer = new WriterThread(lock); + writer.start(); + Thread.sleep(1000); + // The writer should have acquired the lock + assertTrue(writer.acquiredLock); + // Stop the readers + for(int i = 0; i < readers.length; i++) readers[i].interrupt(); + } + + private static class ReaderThread extends Thread { + + private final ReentrantReadWriteLock lock; + + private ReaderThread(ReentrantReadWriteLock lock) { + this.lock = lock; + } + + @Override + public void run() { + try { + while(true) { + lock.readLock().lock(); + try { + Thread.sleep(13); + } finally { + lock.readLock().unlock(); + } + } + } catch(InterruptedException quit) { + return; + } + } + } + + private static class WriterThread extends Thread { + + private final ReentrantReadWriteLock lock; + private volatile boolean acquiredLock = false; + + private WriterThread(ReentrantReadWriteLock lock) { + this.lock = lock; + } + + @Override + public void run() { + lock.writeLock().lock(); + try { + acquiredLock = true; + } finally { + lock.writeLock().unlock(); + } + } + } +}