blob: c022d9c00bff0f3747830c3e8e2b2f277193a000 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2012 Broadcom Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* James Blackburn (Broadcom Corp.) - initial API and implementation
*******************************************************************************/
package org.eclipse.core.tests.runtime.jobs;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.tests.harness.TestBarrier;
/**
* Regression test for bug 311863
* Interrupting a thread, just as it acquires a lock, loses the lock and deadlocks
* occurs if another thread is in the queue waiting for the lock
*/
public class Bug_311863 extends AbstractJobManagerTest {
/** Signal to the threads that we're done */
volatile boolean finished = false;
final int WAIT_ACQUIRE = 10002;
final int RELEASED = 10013;
final int DONE = 10023;
final ILock lock = Job.getJobManager().newLock();
/**
* Test thread that tries to acquire the lock,
* yields and sleeps
*/
class TestThread extends Thread {
private final TestBarrier tb;
private final int yield_time;
public TestThread(TestBarrier tb, int yield_time) {
this.tb = tb;
this.yield_time = yield_time;
}
public void run() {
while (true) {
tb.waitForStatus(WAIT_ACQUIRE);
if (finished)
break;
for (int i = 0; i < 5; i++) {
lock.acquire();
try {
Thread.sleep(yield_time);
Thread.yield();
} catch (InterruptedException e) {
}
lock.release();
Thread.interrupted();
}
tb.setStatus(RELEASED);
}
tb.setStatus(DONE);
}
}
/**
* Threads: main, t1, t2, t3
* Locks: lock1
*
* All three threads try to acquire and release lock1 while being concurrently
* interrupted.
*
* What goes wrong in this:
* Say t1 holds lock1.
* If t2 is interrupted *just* as t1 releases the lock. t2's released
* semaphore is discarded leading to deadlock as t1 gets put behind
* t3 in the queue to acquire the lock.
*
* Particularly insidious as the UI thread is interrupted frequently
*
* @throws Exception
*/
public void testInterruptDuringLockRelease() throws Exception {
final TestBarrier tb1 = new TestBarrier(-1);
final TestBarrier tb2 = new TestBarrier(-1);
final TestBarrier tb3 = new TestBarrier(-1);
// The threads that will fight over the lock
Thread t1 = new TestThread(tb1, 1);
Thread t2 = new TestThread(tb2, 2);
Thread t3 = new TestThread(tb3, 3);
// Start the threads
t1.start();
t2.start();
t3.start();
// iterations
for (int i = 0; i < 10; i++) {
// t1, t2, t3 fight for the lock
tb1.setStatus(WAIT_ACQUIRE);
tb2.setStatus(WAIT_ACQUIRE);
tb3.setStatus(WAIT_ACQUIRE);
// Comment out makes the test pass
for (int j = 0; j < 10; j++) {
t1.interrupt();
t2.interrupt();
t3.interrupt();
Thread.yield();
}
// Release everything and start again
tb1.waitForStatus(RELEASED);
tb2.waitForStatus(RELEASED);
tb3.waitForStatus(RELEASED);
// System.out.println("Success " + i);
}
finished = true;
// release the threads
tb1.setStatus(WAIT_ACQUIRE);
tb2.setStatus(WAIT_ACQUIRE);
tb3.setStatus(WAIT_ACQUIRE);
// wait for them to go away
tb1.waitForStatus(DONE);
tb2.waitForStatus(DONE);
tb3.waitForStatus(DONE);
}
}