/*******************************************************************************
 * Copyright (c) 2009, 2018 IBM 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.core.tests.runtime.jobs;

import java.util.*;
import java.util.concurrent.Semaphore;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.*;
import org.eclipse.core.tests.harness.TestBarrier;
import org.eclipse.core.tests.harness.TestJob;

/**
 * Tests for {@link Job#yieldRule(IProgressMonitor)}.
 */
public class YieldTest extends AbstractJobManagerTest {

	class TestJobListener extends JobChangeAdapter {
		private Set<Job> scheduled = Collections.synchronizedSet(new HashSet<Job>());

		public void cancelAllJobs() {
			Job[] jobs = scheduled.toArray(new Job[0]);
			for (Job job : jobs) {
				job.cancel();
			}
		}

		@Override
		public void done(IJobChangeEvent event) {
			synchronized (YieldTest.this) {
				if (scheduled.remove(event.getJob())) {
					//wake up the waitForCompletion method
					completedJobs++;
					YieldTest.this.notify();
				}
			}
		}

		@Override
		public void scheduled(IJobChangeEvent event) {
			Job job = event.getJob();
			synchronized (YieldTest.this) {
				if (job instanceof TestJob) {
					scheduledJobs++;
					scheduled.add(job);
				}
			}
		}
	}

	protected int completedJobs;

	private IJobChangeListener[] jobListeners;

	protected int scheduledJobs;

	public YieldTest(String name) {
		super(name);
	}

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		completedJobs = 0;
		scheduledJobs = 0;
		jobListeners = new IJobChangeListener[] {/* new VerboseJobListener(),*/
		new TestJobListener()};
		for (IJobChangeListener jobListener : jobListeners) {
			manager.addJobChangeListener(jobListener);
		}
	}

	@Override
	protected void tearDown() throws Exception {
		for (IJobChangeListener jobListener : jobListeners) {
			if (jobListener instanceof TestJobListener) {
				((TestJobListener) jobListener).cancelAllJobs();
			}
		}
		waitForCompletion();
		for (IJobChangeListener jobListener : jobListeners) {
			manager.removeJobChangeListener(jobListener);
		}
		super.tearDown();
	}

	public void testExceptionWhenYieldingNotOwner() {
		int[] location = new int[2];
		final TestBarrier barrier1 = new TestBarrier(location, 0);
		final TestBarrier barrier2 = new TestBarrier(location, 1);

		final Job yielding = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier2.setStatus(TestBarrier.STATUS_START);
				barrier1.waitForStatus(TestBarrier.STATUS_START);
				return Status.OK_STATUS;
			}
		};
		Job otherJob = new Job(getName() + " ShouldFault") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier2.waitForStatus(TestBarrier.STATUS_START);
				try {
					yielding.yieldRule(null);
				} catch (IllegalArgumentException e) {
					//expected
					return new Status(IStatus.ERROR, "org.eclipse.core.tests.runtime", "Expected failure");
				} finally {
					barrier1.setStatus(TestBarrier.STATUS_START);
				}
				return Status.OK_STATUS;
			}
		};
		yielding.schedule();
		otherJob.schedule();

		waitForCompletion(otherJob);
		assertTrue(!otherJob.getResult().isOK());
		waitForCompletion(yielding);
	}

	public void testExceptionWhenYieldingNotRunning() {
		final Job yielding = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				return Status.OK_STATUS;
			}
		};
		try {
			yielding.yieldRule(null);
			fail("Did not throw exception");
		} catch (IllegalArgumentException e) {
			// ignore
		}

	}

	public void testThreadRestored() {
		final PathRule rule = new PathRule(getName());

		final Job[] jobs = new Job[2];
		Job yieldJob = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				assertNull("Conflicting job result is not null: " + jobs[1].getResult(), jobs[1].getResult());
				Thread before = getThread();
				while (yieldRule(null) == null) {
					//loop until yield succeeds
				}
				waitForCompletion(jobs[1]);
				Thread after = getThread();
				assertEquals("Thread not restored", before, after);
				assertTrue("Conflicting job not done", jobs[1].getResult().isOK());
				assertTrue("Conflicting job still running", jobs[1].getState() == Job.NONE);
				return Status.OK_STATUS;
			}
		};
		jobs[0] = yieldJob;
		yieldJob.setRule(rule);

		Job conflictingJob = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				assertTrue(jobs[0].getState() == WAITING);
				assertTrue(jobs[0].getResult() == null);
				return Status.OK_STATUS;
			}
		};
		jobs[1] = conflictingJob;
		conflictingJob.setRule(rule);

		yieldJob.schedule();
		conflictingJob.schedule();
		waitForCompletion(yieldJob);
		assertTrue("Result is not ok: " + yieldJob.getResult(), yieldJob.getResult().isOK());
		waitForCompletion(conflictingJob);
		assertTrue(conflictingJob.getResult().isOK());
	}

	public void testYieldJobToJob() {
		final PathRule rule = new PathRule(getName());

		final Job[] jobs = new Job[2];
		Job yieldJob = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				assertTrue(jobs[1].getResult() == null);
				while (yieldRule(null) == null) {
					//loop until yield succeeds
				}
				waitForCompletion(jobs[1]);
				assertTrue(jobs[1].getResult().isOK());
				assertTrue(jobs[1].getState() == Job.NONE);
				return Status.OK_STATUS;
			}
		};
		jobs[0] = yieldJob;
		yieldJob.setRule(rule);

		Job conflictingJob = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				assertEquals(WAITING, jobs[0].getState());
				assertTrue(jobs[0].getResult() == null);
				return Status.OK_STATUS;
			}
		};
		jobs[1] = conflictingJob;
		conflictingJob.setRule(rule);

		yieldJob.schedule();
		conflictingJob.schedule();
		waitForCompletion(yieldJob);
		final IStatus yieldResult = yieldJob.getResult();
		if (!yieldResult.isOK()) {
			Throwable t = yieldResult.getException();
			if (t != null) {
				fail("yieldJob failed", t);
			}
			fail("yieldJob failed:" + yieldResult);
		}
		waitForCompletion(conflictingJob);
		assertTrue(conflictingJob.getResult().isOK());
	}

	//	public void testILockTransfer() {
	//		final PathRule rule = new PathRule("testYield");
	//		final ILock lock = Job.getJobManager().newLock();
	//		final Job[] jobs = new Job[2];
	//		final IStatus[] results = new IStatus[2];
	//		Job yieldJob = new Job("Yielding") {
	//			protected IStatus run(IProgressMonitor monitor) {
	//				assertTrue(results[1] == null);
	//				assertTrue(jobs[1].getState() == Job.WAITING);
	//				lock.acquire();
	//				while (true)
	//					if (yield())
	//						break;
	//				assertTrue(results[1].isOK());
	//				assertTrue(jobs[1].getState() == Job.NONE);
	//				return Status.OK_STATUS;
	//			}
	//		};
	//		jobs[0] = yieldJob;
	//		yieldJob.setRule(rule);
	//		yieldJob.addJobChangeListener(new YieldJobListener(results, 0));
	//
	//		Job conflictingJob = new Job("Conflicting") {
	//			protected IStatus run(IProgressMonitor monitor) {
	//				lock.acquire();
	//				assertTrue(jobs[0].getState() == WAITING);
	//				assertTrue(results[0] == null);
	//				return Status.OK_STATUS;
	//			}
	//		};
	//		jobs[1] = conflictingJob;
	//		conflictingJob.setRule(rule);
	//		conflictingJob.addJobChangeListener(new YieldJobListener(results, 1));
	//
	//		yieldJob.schedule();
	//		conflictingJob.schedule();
	//		waitForCompletion(yieldJob);
	//		assertTrue(yieldJob.getResult().isOK());
	//		waitForCancel(conflictingJob);
	//		assertTrue(conflictingJob.getResult().isOK());
	//	}

	public void testYieldJobToJobAndEnsureConflictingRunsBeforeResume() {
		final PathRule rule = new PathRule(getName());
		int[] location = new int[2];
		final TestBarrier barrier1 = new TestBarrier(location, 0);
		final Job[] jobs = new Job[2];
		Job yieldJob = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier1.waitForStatus(TestBarrier.STATUS_START);
				barrier1.setStatus(TestBarrier.STATUS_RUNNING);
				while (yieldRule(null) == null) {
					//loop until yield succeeds
				}
				barrier1.waitForStatus(TestBarrier.STATUS_DONE);
				return Status.OK_STATUS;
			}
		};
		jobs[0] = yieldJob;
		yieldJob.setRule(rule);

		final Job conflictingJob1 = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier1.setStatus(TestBarrier.STATUS_DONE);
				return Status.OK_STATUS;
			}
		};
		conflictingJob1.setRule(rule);

		Job nonConflict = new Job(getName() + " Non-conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				return Status.OK_STATUS;
			}
		};

		yieldJob.schedule();
		conflictingJob1.schedule();
		barrier1.setStatus(TestBarrier.STATUS_START);
		// we are testing a race-condition here... (This test will not catch all conditions)
		// make sure starting a non-conflicting job does not cause
		// the yielding job to resume before conflicting job has a chance to run
		nonConflict.schedule(1);

		waitForCompletion(yieldJob);
		waitForCompletion(conflictingJob1);
		waitForCompletion(nonConflict);
		assertTrue(yieldJob.getResult().isOK());
		assertTrue(conflictingJob1.getResult().isOK());
		assertTrue(nonConflict.getResult().isOK());
	}

	public void testYieldJobToThread() {

		final PathRule rule = new PathRule(getName());
		final TestBarrier barrier = new TestBarrier();
		final Job yielding = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier.setStatus(TestBarrier.STATUS_START);
				while (yieldRule(null) == null) {
					//loop until yield succeeds
				}
				// ensure that the other job ran
				barrier.waitForStatus(TestBarrier.STATUS_DONE);
				return Status.OK_STATUS;
			}
		};
		yielding.setRule(rule);
		Thread t = new Thread(getName() + " Conflicting") {
			@Override
			public void run() {
				try {
					Job.getJobManager().beginRule(rule, null);
					barrier.setStatus(TestBarrier.STATUS_DONE);
				} finally {
					Job.getJobManager().endRule(rule);
				}
			}
		};

		yielding.schedule();
		barrier.waitForStatus(TestBarrier.STATUS_START);
		t.start();

		waitForCompletion(yielding);
		assertTrue(yielding.getResult().isOK());
	}

	public void testYieldThreadJobToThread() {
		final PathRule rule = new PathRule(getName());
		final TestBarrier barrier = new TestBarrier();
		final Job yielding = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				try {
					Job.getJobManager().beginRule(rule, null);
					barrier.setStatus(TestBarrier.STATUS_START);
					while (yieldRule(null) == null) {
						//loop until yield succeeds
					}
					// ensure that the other job ran
					barrier.waitForStatus(TestBarrier.STATUS_DONE);
				} finally {
					Job.getJobManager().endRule(rule);
				}
				return Status.OK_STATUS;
			}
		};

		Thread t = new Thread(getName() + " Conflicting") {
			@Override
			public void run() {
				try {
					Job.getJobManager().beginRule(rule, null);
					barrier.setStatus(TestBarrier.STATUS_DONE);
				} finally {
					Job.getJobManager().endRule(rule);
				}
			}
		};

		yielding.schedule();
		barrier.waitForStatus(TestBarrier.STATUS_START);
		t.start();

		waitForCompletion(yielding, 5000);
		assertTrue(yielding.getResult().isOK());
	}

	public void testYieldThreadToJob() {

		final PathRule rule = new PathRule(getName());
		final TestBarrier barrier = new TestBarrier();
		final Thread t = new Thread() {
			@Override
			public void run() {
				IJobManager m = Job.getJobManager();
				try {
					m.beginRule(rule, null);
					Job j = m.currentJob();
					barrier.setStatus(TestBarrier.STATUS_START);
					barrier.waitForStatus(TestBarrier.STATUS_WAIT_FOR_START);
					while (j.yieldRule(null) == null) {
						//loop until yield succeeds
					}
					// ensure that the other job ran
					barrier.waitForStatus(TestBarrier.STATUS_DONE);
				} finally {
					m.endRule(rule);
					barrier.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE);
				}
			}
		};

		final Job conflictingJob = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier.setStatus(TestBarrier.STATUS_DONE);
				return Status.OK_STATUS;
			}
		};

		t.start();
		barrier.waitForStatus(TestBarrier.STATUS_START);
		conflictingJob.setRule(rule);
		conflictingJob.schedule();
		barrier.setStatus(TestBarrier.STATUS_WAIT_FOR_START);
		barrier.waitForStatus(TestBarrier.STATUS_WAIT_FOR_DONE);
		waitForCompletion(conflictingJob);
		assertTrue(conflictingJob.getResult().isOK());
	}

	public void testYieldThreadToThreadJob() {
		final PathRule rule = new PathRule(getName());
		final TestBarrier barrier = new TestBarrier();
		Thread t = new Thread(getName() + " Yielding") {
			@Override
			public void run() {
				try {
					Job.getJobManager().beginRule(rule, null);
					barrier.setStatus(TestBarrier.STATUS_START);
					while (Job.getJobManager().currentJob().yieldRule(null) == null) {
						//loop until yield succeeds
					}
					// ensure that the other job ran
					barrier.waitForStatus(TestBarrier.STATUS_DONE);
				} finally {
					Job.getJobManager().endRule(rule);
				}
				// status code irrelevant
				barrier.setStatus(TestBarrier.STATUS_BLOCKED);
			}
		};

		final Job conflicting = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				try {
					Job.getJobManager().beginRule(rule, null);
				} finally {
					Job.getJobManager().endRule(rule);
				}
				barrier.setStatus(TestBarrier.STATUS_DONE);
				return Status.OK_STATUS;
			}
		};

		t.start();
		barrier.waitForStatus(TestBarrier.STATUS_START);
		conflicting.schedule();

		waitForCompletion(conflicting, 5000);
		assertTrue(conflicting.getResult().isOK());
		barrier.waitForStatus(TestBarrier.STATUS_BLOCKED);
	}

	private synchronized void waitForCompletion() {
		int i = 0;
		assertTrue("Jobs completed that weren't scheduled", completedJobs <= scheduledJobs);
		while (completedJobs < scheduledJobs) {
			try {
				wait(500);
			} catch (InterruptedException e) {
				//ignore
			}
			//sanity test to avoid hanging tests
			if (i++ > 1000) {
				dumpState();
				assertTrue("Timeout waiting for job to complete", false);
			}
		}
	}

	public void transferRuleToYieldingThreadJobException() {
		final TestBarrier barrier = new TestBarrier();
		final PathRule rule = new PathRule(getName());

		final Thread A = new Thread() {
			@Override
			public void run() {
				try {
					Job.getJobManager().beginRule(rule, null);
					barrier.setStatus(TestBarrier.STATUS_RUNNING);
					while (Job.getJobManager().currentJob().yieldRule(null) == null) {
						//loop until yield succeeds
					}

				} finally {
					Job.getJobManager().endRule(rule);
				}
			}
		};

		Thread B = new Thread() {
			@Override
			public void run() {
				barrier.waitForStatus(TestBarrier.STATUS_RUNNING);

				try {
					Job.getJobManager().beginRule(rule, null);

					// transfer it back to other thread -
					// this will cause exception since the target thread already owns
					// this rule
					try {
						Job.getJobManager().transferRule(rule, A);
					} catch (Exception e) {
						barrier.setStatus(TestBarrier.STATUS_DONE);
					}
				} finally {
					Job.getJobManager().endRule(rule);

				}

			}
		};
		A.start();
		B.start();
		barrier.waitForStatus(TestBarrier.STATUS_DONE);
	}

	public void transferRuleToYieldingJobException() {
		final TestBarrier barrier = new TestBarrier();
		final PathRule rule = new PathRule(getName());

		final Thread[] t = new Thread[1];
		final Job A = new Job(getName() + "A") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				t[0] = getThread();
				try {
					Job.getJobManager().beginRule(rule, null);
					barrier.setStatus(TestBarrier.STATUS_RUNNING);
					while (Job.getJobManager().currentJob().yieldRule(null) == null) {
						//loop until yield succeeds
					}

				} finally {
					Job.getJobManager().endRule(rule);
				}
				return Status.OK_STATUS;
			}

		};
		Job B = new Job(getName() + "B") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier.waitForStatus(TestBarrier.STATUS_RUNNING);

				try {
					Job.getJobManager().beginRule(rule, null);

					// transfer it back to other thread -
					// this will cause exception since the target thread already owns
					// this rule
					try {
						Job.getJobManager().transferRule(rule, t[0]);
					} catch (Exception e) {
						barrier.setStatus(TestBarrier.STATUS_DONE);
					}
				} finally {
					Job.getJobManager().endRule(rule);
				}
				return Status.OK_STATUS;
			}
		};
		A.schedule();
		B.schedule();
		barrier.waitForStatus(TestBarrier.STATUS_DONE);
	}

	public void testYieldPingPong() {
		// yield from one job, then yield again
		final PathRule rule = new PathRule(getName());

		final Job[] jobs = new Job[2];
		Job yieldJob = new Job(getName() + " Yielding") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				assertTrue(jobs[1].getResult() == null);
				while (yieldRule(null) == null) {
					//loop until yield succeeds
				}
				assertTrue(jobs[1].getState() == Job.WAITING);
				return Status.OK_STATUS;
			}
		};
		jobs[0] = yieldJob;
		yieldJob.setRule(rule);

		Job conflictingJob = new Job(getName() + " ConflictingJob1") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				assertEquals(WAITING, jobs[0].getState());
				while (yieldRule(null) == null) {
					//loop until yield succeeds
				}
				assertEquals(NONE, jobs[0].getState());
				return Status.OK_STATUS;
			}
		};
		jobs[1] = conflictingJob;
		conflictingJob.setRule(rule);

		yieldJob.schedule();
		conflictingJob.schedule();
		waitForCompletion(yieldJob);
		final IStatus yieldResult = yieldJob.getResult();
		if (!yieldResult.isOK()) {
			Throwable t = yieldResult.getException();
			if (t != null) {
				fail("yieldJob failed", t);
			}
			fail("yieldJob failed:" + yieldResult);
		}
		waitForCompletion(conflictingJob);
		assertTrue(conflictingJob.toString(), conflictingJob.getResult().isOK());
	}

	public void testYieldPingPongBetweenMultipleJobs() throws Throwable {
		final TestBarrier barrier = new TestBarrier();
		final PathRule rule = new PathRule(getName());
		final Object SYNC = new Object();
		final int count = 100;
		final Integer[] started = new Integer[] {Integer.valueOf(0)};
		final List<Job> jobs = new ArrayList<>();
		for (int i = 0; i < count; i++) {
			Job conflictingJob = new Job(getName() + " ConflictingJob" + i) {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					synchronized (SYNC) {
						started[0] = Integer.valueOf(started[0].intValue() + 1);
						SYNC.notifyAll();
					}
					barrier.waitForStatus(TestBarrier.STATUS_WAIT_FOR_START);
					while (true) {

						if (yieldRule(null) != null) {
							break;
						}

						if (getFinishedJobs(jobs.toArray(new Job[jobs.size()])).size() == count - 1) {
							System.out.println(this + " Ended via no more jobs to yield");
							break;
						}

						//loop until yield succeeds
					}
					return Status.OK_STATUS;
				}
			};
			conflictingJob.setRule(rule);
			jobs.add(conflictingJob);
		}

		for (Job conflict : jobs) {
			conflict.schedule();
		}

		// wait for jobs to start running
		synchronized (SYNC) {
			while (started[0].intValue() != count) {
				try {
					SYNC.wait();
				} catch (InterruptedException e) {
					fail("4.99", e);
				}
			}
		}
		// release all waiting jobs
		barrier.setStatus(TestBarrier.STATUS_WAIT_FOR_START);
		// wait for jobs to finish within 5s
		waitForJobsCompletion(jobs.toArray(new Job[jobs.size()]), 5000);

		for (Job conflict : jobs) {
			assertNotNull("Null result for " + conflict, conflict.getResult());
			assertTrue(conflict.getResult().isOK());
		}

	}

	public void testParallelYieldPingPongBetweenMultipleJobs() throws Throwable {
		// same as above, but use two conflicting job families and make sure they don't interfere

		final int count = 10;

		//----------
		// FAMILY A
		//----------

		final TestBarrier barrier_A = new TestBarrier();
		final PathRule rule_A = new PathRule(getName() + "_ruleA");
		final Object SYNC_A = new Object();
		final Integer[] started_A = new Integer[] {Integer.valueOf(0)};
		final List<Job> jobs_A = new ArrayList<>();
		for (int i = 0; i < count; i++) {
			Job conflictingJob = new Job(getName() + " ConflictingJob_A_" + i) {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					synchronized (SYNC_A) {
						started_A[0] = Integer.valueOf(started_A[0].intValue() + 1);
						SYNC_A.notifyAll();
					}
					barrier_A.waitForStatus(TestBarrier.STATUS_WAIT_FOR_START);
					while (true) {

						if (yieldRule(null) != null) {
							break;
						}

						if (getFinishedJobs(jobs_A.toArray(new Job[jobs_A.size()])).size() == count - 1) {
							System.out.println(this + " Ended via no more jobs to yield");
							break;
						}

						//loop until yield succeeds
					}
					return Status.OK_STATUS;
				}
			};
			conflictingJob.setRule(rule_A);
			jobs_A.add(conflictingJob);
		}

		for (Job conflict : jobs_A) {
			conflict.schedule();
		}

		// wait for jobs to start running
		synchronized (SYNC_A) {
			while (started_A[0].intValue() != count) {
				try {
					SYNC_A.wait();
				} catch (InterruptedException e) {
					fail("4.99", e);
				}
			}
		}
		// release all waiting jobs
		barrier_A.setStatus(TestBarrier.STATUS_WAIT_FOR_START);

		//----------
		// FAMILY B
		//----------

		final TestBarrier barrier_B = new TestBarrier();
		final PathRule rule_B = new PathRule(getName() + "_ruleB");
		final Object SYNC_B = new Object();

		final Integer[] started_B = new Integer[] { Integer.valueOf(0) };
		final List<Job> jobs_B = new ArrayList<>();
		for (int i = 0; i < count; i++) {
			Job conflictingJob = new Job(getName() + " ConflictingJob_B_" + i) {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					synchronized (SYNC_B) {
						started_B[0] = Integer.valueOf(started_B[0].intValue() + 1);
						SYNC_B.notifyAll();
					}
					barrier_B.waitForStatus(TestBarrier.STATUS_WAIT_FOR_START);
					while (true) {

						if (yieldRule(null) != null) {
							break;
						}

						if (getFinishedJobs(jobs_B.toArray(new Job[jobs_B.size()])).size() == count - 1) {
							System.out.println(this + " Ended via no more jobs to yield");
							break;
						}

						//loop until yield succeeds
					}
					return Status.OK_STATUS;
				}
			};
			conflictingJob.setRule(rule_B);
			jobs_B.add(conflictingJob);
		}

		for (Job conflict : jobs_B) {
			conflict.schedule();
		}

		// wait for jobs to start running
		synchronized (SYNC_B) {
			while (started_B[0].intValue() != count) {
				try {
					SYNC_B.wait();
				} catch (InterruptedException e) {
					fail("4.99", e);
				}
			}
		}
		// release all waiting jobs
		barrier_B.setStatus(TestBarrier.STATUS_WAIT_FOR_START);

		// wait for jobs to finish within 5s
		waitForJobsCompletion(jobs_A.toArray(new Job[jobs_A.size()]), 5000);

		// wait for jobs to finish within 5s
		waitForJobsCompletion(jobs_B.toArray(new Job[jobs_B.size()]), 5000);

		for (Job conflict : jobs_A) {
			assertNotNull("Null result for " + conflict, conflict.getResult());
			assertTrue(conflict.getResult().isOK());
		}

		for (Job conflict : jobs_B) {
			assertNotNull("Null result for " + conflict, conflict.getResult());
			assertTrue(conflict.getResult().isOK());
		}
	}

	public void testYieldIsInterruptable() throws Exception {
		Semaphore semaphoreA = new Semaphore(0);
		Semaphore semaphoreB = new Semaphore(0);
		Semaphore mainThreadSemaphore = new Semaphore(0);
		final PathRule rule = new PathRule(getName());
		String[] failureMessage = new String[1];
		boolean[] operationWasCanceled = new boolean[1];
		final Job yieldB = new Job(getName() + " YieldingB") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				// Step 2
				semaphoreA.release();
				try {
					// Block until thread yieldA reaches step 3
					semaphoreB.acquire();
				} catch (InterruptedException e) {
					failureMessage[0] = "yieldB was interrupted too early";
					return Status.OK_STATUS;
				}
				// Step 5
				mainThreadSemaphore.release();
				return Status.OK_STATUS;
			}
		};
		Job yieldA = new Job(getName() + " YieldingA") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				try {
					// Block until the main thread reaches step 1
					semaphoreA.acquire();
				} catch (InterruptedException e) {
					failureMessage[0] = "yieldA was interrupted too early";
					return Status.OK_STATUS;
				}
				// If this fails to interrupt the following yieldRule call,
				// this thread will deadlock.
				Thread.currentThread().interrupt();
				try {
					// Allow yieldB to start execution
					while (yieldRule(null) != yieldB) {
					}

				} catch (OperationCanceledException e) {
					operationWasCanceled[0] = true;
				}
				if (Thread.interrupted()) {
					failureMessage[0] = "The thread was interrupted after yieldRule returned";
				}
				try {
					// Block until yieldB reaches step 2
					semaphoreA.acquire();
				} catch (InterruptedException e) {
					failureMessage[0] = "yieldA was interrupted too early";
					return Status.OK_STATUS;
				}
				// Step 3
				semaphoreB.release();
				// Step 4
				mainThreadSemaphore.release();
				return Status.OK_STATUS;
			}
		};
		yieldA.setRule(rule);
		yieldA.schedule();

		yieldB.setRule(rule);
		yieldB.schedule();

		// Step 1
		semaphoreA.release();

		// Block until step 4 and step 5 have occurred
		mainThreadSemaphore.acquire(2);
		if (failureMessage[0] != null) {
			assertNull(failureMessage[0], failureMessage[0]);
		}

		assertTrue("yieldRule should have thrown OperationCanceledException", operationWasCanceled[0]);
	}

	public void testYieldJobToJobsInterleaved() {
		// yield from job to multiple waiting others
		final TestBarrier barrier = new TestBarrier();
		final PathRule rule = new PathRule(getName());

		final int count = 50;
		Job yieldA = new Job(getName() + " YieldingA") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier.waitForStatus(TestBarrier.STATUS_START);
				int yields = 0;
				while (yields < count) {
					if (yieldRule(null) != null) {
						yields++;
					}
				}
				return Status.OK_STATUS;
			}
		};
		yieldA.setRule(rule);
		yieldA.schedule();

		Job yieldB = new Job(getName() + " YieldingB") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				barrier.waitForStatus(TestBarrier.STATUS_START);
				int yields = 0;
				while (yields < count) {
					if (yieldRule(null) != null) {
						yields++;
					}
				}
				return Status.OK_STATUS;
			}
		};
		yieldB.setRule(rule);
		yieldB.schedule();

		barrier.setStatus(TestBarrier.STATUS_START);

		List<Job> jobs = new ArrayList<>();
		jobs.add(yieldA);
		jobs.add(yieldB);

		// wait for jobs to start
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			fail("4.99", e);
		}
		waitForJobsCompletion(jobs.toArray(new Job[jobs.size()]), 20000);
		for (Job conflict : jobs) {
			assertTrue(conflict.getResult().isOK());
		}
	}

	public void testYieldThreadJobToBlockedConflictingJob() throws Exception {
		final PathRule rule = new PathRule(getName());
		final TestBarrier b = new TestBarrier(TestBarrier.STATUS_START);
		final Job yieldA = new Job(getName()) {
			@Override
			protected IStatus run(IProgressMonitor monitor) {

				try {
					Job.getJobManager().beginRule(rule, monitor);
					b.setStatus(TestBarrier.STATUS_RUNNING);
					while (yieldRule(null) == null && !monitor.isCanceled()) {
						//loop until yield succeeds
					}
				} finally {
					Job.getJobManager().endRule(rule);
				}

				return Status.OK_STATUS;
			}
		};
		Job conflicting = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				return Status.OK_STATUS;
			}
		};
		conflicting.setRule(rule);

		// start testing

		yieldA.schedule();
		b.waitForStatus(TestBarrier.STATUS_RUNNING);
		conflicting.schedule();
		try {
			waitForCompletion(yieldA);
			waitForCompletion(conflicting);
		} finally {
			//always cleanup even if we fail
			yieldA.cancel();
		}

	}

	public void testResumingThreadJobIsNotRescheduled() {

		final PathRule rule = new PathRule(getName());
		final TestBarrier b = new TestBarrier(TestBarrier.STATUS_START);
		final Job yieldA = new Job(getName()) {
			@Override
			protected IStatus run(IProgressMonitor monitor) {

				try {
					Job.getJobManager().beginRule(rule, monitor);
					b.setStatus(TestBarrier.STATUS_RUNNING);
					while (yieldRule(null) == null) {
						if (monitor.isCanceled()) {
							return Status.CANCEL_STATUS;
						//loop until yield succeeds
						}
					}
				} finally {
					Job.getJobManager().endRule(rule);
				}

				return Status.OK_STATUS;
			}
		};
		final Job conflicting = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				return Status.OK_STATUS;
			}
		};
		conflicting.setRule(rule);

		final int[] count = new int[1];
		JobChangeAdapter a = new JobChangeAdapter() {
			@Override
			public void running(org.eclipse.core.runtime.jobs.IJobChangeEvent event) {
				if (event.getJob() == yieldA) {
					count[0]++;
				}
			}
		};
		Job.getJobManager().addJobChangeListener(a);

		// start testing

		yieldA.schedule();
		b.waitForStatus(TestBarrier.STATUS_RUNNING);
		conflicting.schedule();
		try {
			waitForCompletion(yieldA);
			waitForCompletion(conflicting);
			assertEquals("While resuming from yieldRule, implicit Job should only run once", 1, count[0]);
		} finally {
			//clean up even if the test fails
			yieldA.cancel();
			Job.getJobManager().removeJobChangeListener(a);
		}

	}

	public void testNestedAcquireJobIsNotRescheduled() {

		final PathRule rule = new PathRule(getName());
		final PathRule subRule = new PathRule(getName() + "/subRule");

		final TestBarrier b = new TestBarrier(TestBarrier.STATUS_START);
		final Job yieldA = new Job(getName()) {
			@Override
			protected IStatus run(IProgressMonitor monitor) {

				b.setStatus(TestBarrier.STATUS_RUNNING);
				try {
					Job.getJobManager().beginRule(subRule, null);

					while (yieldRule(null) == null) {
						//loop until yield succeeds
					}
				} finally {
					Job.getJobManager().endRule(subRule);
				}

				return Status.OK_STATUS;
			}
		};
		yieldA.setRule(rule);

		final Job conflicting = new Job(getName() + " Conflicting") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				return Status.OK_STATUS;
			}
		};
		conflicting.setRule(rule);

		final int[] count = new int[1];
		JobChangeAdapter a = new JobChangeAdapter() {
			@Override
			public void running(org.eclipse.core.runtime.jobs.IJobChangeEvent event) {
				if (event.getJob() == conflicting) {
					count[0]++;
				}
			}
		};
		Job.getJobManager().addJobChangeListener(a);
		try {
			// start testing
			yieldA.schedule();
			b.waitForStatus(TestBarrier.STATUS_RUNNING);
			conflicting.schedule();
			waitForCompletion(yieldA);
			waitForCompletion(conflicting);
			assertEquals("While resuming from yieldRule, conflicting job should only run once", 1, count[0]);
		} finally {
			Job.getJobManager().removeJobChangeListener(a);
		}
	}

}
