/*******************************************************************************
 * Copyright (c) 2010, 2015 Broadcom Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * 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 307282
 * This tests that a thread interrupted while it attempts to acquire a lock
 * doesn't break any future acquires of the lock.
 */
public class Bug_307282 extends AbstractJobManagerTest {

	/**
	 * Threads: main, t1, t2
	 * Locks: l1, l2
	 *
	 * t1 owns l1; t2 own l2
	 * t2 attempts acquire of l1
	 * main interrupt()s t2
	 * t1 release l1
	 * main attempt acquire() l1
	 *
	 * @throws Exception
	 */
	public void testInterruptDuringLockAcquireint() throws Exception {

		final ILock lock1 = Job.getJobManager().newLock();
		final ILock lock2 = Job.getJobManager().newLock();

		final TestBarrier tb1 = new TestBarrier(-1);
		final TestBarrier tb2 = new TestBarrier(-1);

		final int INTERRUPTED = 1000;
		final int RELEASE_LOCK = 10001;

		Thread t = new Thread() {
			@Override
			public void run() {
				lock1.acquire();

				tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_START);
				tb1.waitForStatus(TestBarrier.STATUS_START);

				tb1.waitForStatus(RELEASE_LOCK);
				lock1.release();

				tb1.waitForStatus(TestBarrier.STATUS_WAIT_FOR_DONE);
				tb1.setStatus(TestBarrier.STATUS_DONE);
			}
		};

		Thread t2 = new Thread() {
			@Override
			public void run() {
				lock2.acquire();

				tb2.setStatus(TestBarrier.STATUS_WAIT_FOR_START);
				tb2.waitForStatus(TestBarrier.STATUS_START);

				// Now attempt acquire lock1 with an integer delay
				try {
					assertTrue(!lock1.acquire(60 * 1000));
				} catch (InterruptedException e) {
					tb2.setStatus(INTERRUPTED);
				}

				tb2.waitForStatus(RELEASE_LOCK);
				lock2.release();

				tb2.waitForStatus(TestBarrier.STATUS_WAIT_FOR_DONE);
				tb2.setStatus(TestBarrier.STATUS_DONE);
			}
		};

		// Start the threads
		t.start();
		t2.start();

		// wait for the threads to get to start and acquire first lock
		tb1.waitForStatus(TestBarrier.STATUS_WAIT_FOR_START);
		tb2.waitForStatus(TestBarrier.STATUS_WAIT_FOR_START);
		// now let thread 2 attempt to acquire lock 2
		tb1.setStatus(TestBarrier.STATUS_START);
		tb2.setStatus(TestBarrier.STATUS_START);
		Thread.sleep(1000); // not-so-small sleep so thread 2 is definitely in the acquire

		// Interrupt thread 2 while it's waiting for lock1
		t2.interrupt();
		tb2.waitForStatus(INTERRUPTED);

		// thread 1 release lock 1
		tb1.setStatus(RELEASE_LOCK);

		// We should now be able to acquire lock1 without difficulty
		assertTrue(lock1.acquire(1000));
		// T2 should still hold the lock2
		assertTrue(!lock2.acquire(0));

		tb2.setStatus(RELEASE_LOCK);
		assertTrue(lock2.acquire(1000));

		tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE);
		tb2.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE);
		tb1.waitForStatus(TestBarrier.STATUS_DONE);
		tb2.waitForStatus(TestBarrier.STATUS_DONE);
	}
}
