use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class ExecutionSemaphore method acquire.
/**
* Acquires a permit from this semaphore, blocking until one is available, or the thread is interrupted.
*
* @param task
* the task to acquire a permit for.
* @param queuePosition
* the position where to place the task in the queue of competing tasks if no permit is free at the time of
* invocation.
* @throws ThreadInterruptedError
* if the current thread was interrupted while waiting.
*/
protected void acquire(final IFuture<?> task, final QueuePosition queuePosition) {
assertSameSemaphore(task);
final Object acquisitionLock = new Object();
final AtomicBoolean waitingForPermit = new AtomicBoolean(true);
compete(task, queuePosition, new IPermitAcquiredCallback() {
@Override
public void onPermitAcquired() {
synchronized (acquisitionLock) {
if (waitingForPermit.get()) {
acquisitionLock.notify();
} else {
release(task);
}
}
}
});
// Block the current thread until a permit is acquired.
synchronized (acquisitionLock) {
while (!isPermitOwner(task)) {
try {
acquisitionLock.wait();
} catch (final java.lang.InterruptedException e) {
// Restore the interrupted status because cleared by catching InterruptedException.
Thread.currentThread().interrupt();
waitingForPermit.set(false);
throw new ThreadInterruptedError("Interrupted while competing for a permit").withContextInfo("task", task.getJobInput().getName()).withContextInfo("executionSemaphore", this);
}
}
}
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class TimeoutClientRunContextStatement method evaluate.
@Override
public void evaluate() throws Throwable {
final SafeStatementInvoker invoker = new SafeStatementInvoker(m_next);
final IFuture<Void> future = ModelJobs.schedule(invoker, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("Running test with support for JUnit timeout"));
try {
if (m_timeoutMillis <= 0) {
future.awaitDone();
} else {
future.awaitDone(m_timeoutMillis, TimeUnit.MILLISECONDS);
}
} catch (ThreadInterruptedError | TimedOutError e) {
// NOSONAR
future.cancel(true);
// JUnit timeout exception
throw new TestTimedOutException(m_timeoutMillis, TimeUnit.MILLISECONDS);
}
invoker.throwOnError();
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class AbstractSmartField2 method fetchLookupRows.
/**
* Loads lookup rows according to the specified {@link ILookupRowProvider}, and notifies the specified callback upon
* fetching completed.
*
* @return {@link IFuture} if data is fetched asynchronously, or <code>null</code> for synchronous fetching, or if
* using {@link LocalLookupCall}.
*/
private IFuture<Void> fetchLookupRows(final ILookupRowProvider<VALUE> dataProvider, final ILookupRowFetchedCallback<VALUE> callback, final boolean asynchronousFetching, final int maxRowCount) {
cancelPotentialLookup();
if (getLookupCall() == null) {
callback.onSuccess(Collections.<ILookupRow<VALUE>>emptyList());
return null;
}
// Prepare the lookup call.
final ILookupCall<VALUE> lookupCall = cloneLookupCall();
lookupCall.setMaxRowCount(maxRowCount > 0 ? maxRowCount : getBrowseMaxRowCount());
// Prepare processing of the fetched rows.
final ILookupRowFetchedCallback<VALUE> internalCallback = new ILookupRowFetchedCallback<VALUE>() {
@Override
public void onSuccess(final List<? extends ILookupRow<VALUE>> rows) {
joinModelThreadAndUpdateField(rows, null);
}
@Override
public void onFailure(final RuntimeException e) {
joinModelThreadAndUpdateField(null, e);
}
private void joinModelThreadAndUpdateField(final List<? extends ILookupRow<VALUE>> rows, final RuntimeException exception) {
if (ModelJobs.isModelThread()) {
updateField(rows, exception);
} else {
// Note: The model job will not commence execution if the current ClientRunContext is or gets cancelled.
try {
ClientRunContext callerRunContext = ClientRunContexts.copyCurrent();
if (callerRunContext.getRunMonitor().isCancelled()) {
return;
}
ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
updateField(rows, exception);
}
}, ModelJobs.newInput(callerRunContext).withName("Updating {}", AbstractSmartField2.this.getClass().getName())).awaitDone();
} catch (ThreadInterruptedError e) {
/*
This state can be reached by a race condition when the job's RunMonitor is in canceled state and later the ModelJob is run.
This yields to a Thread.interrupt in the RunContext.ThreadInterrupter...
at RunContext$ThreadInterrupter.cancel(boolean) line: 563
at RunMonitor.cancel(ICancellable, boolean) line: 160
at RunMonitor.registerCancellable(ICancellable) line: 104 <---------------------
at RunContext$ThreadInterrupter.<init>(Thread, RunMonitor) line: 545
at ClientRunContext(RunContext).call(Callable<RESULT>, Class<IExceptionTranslator<EXCEPTION>>) line: 154
at RunContextRunner<RESULT>.intercept(Chain<RESULT>) line: 38
which itself causes the running job to be interrupted with a InterruptedException
at org.eclipse.scout.rt.platform.job.internal.JobExceptionTranslator.translateInterruptedException(JobExceptionTranslator.java:49)
at org.eclipse.scout.rt.platform.job.internal.JobFutureTask.awaitDone(JobFutureTask.java:339)
at org.eclipse.scout.rt.client.ui.form.fields.smartfield2.AbstractSmartField2$7.joinModelThreadAndUpdateField(AbstractSmartField2.java:1598)
at org.eclipse.scout.rt.client.ui.form.fields.smartfield2.AbstractSmartField2$7.onSuccess(AbstractSmartField2.java:1575)
at org.eclipse.scout.rt.shared.services.lookup.LookupCall.loadData(LookupCall.java:437)
at org.eclipse.scout.rt.shared.services.lookup.LookupCall$5.run(LookupCall.java:417)
*/
return;
}
}
}
private void updateField(final List<? extends ILookupRow<VALUE>> rows, final RuntimeException exception) {
try {
if (exception != null) {
// throw to handle exception at the end.
throw exception;
}
final List<ILookupRow<VALUE>> result = new ArrayList<>(rows);
dataProvider.afterProvide(lookupCall, result);
callback.onSuccess(result);
} catch (FutureCancelledError | ThreadInterruptedError e) {
// NOSONAR
callback.onSuccess(Collections.<ILookupRow<VALUE>>emptyList());
} catch (final RuntimeException e) {
callback.onFailure(e);
}
}
};
// Start fetching lookup rows.
IFuture<Void> asyncLookupFuture = null;
try {
dataProvider.beforeProvide(lookupCall);
if (asynchronousFetching) {
asyncLookupFuture = dataProvider.provideAsync(lookupCall, internalCallback, ClientRunContexts.copyCurrent());
} else {
dataProvider.provideSync(lookupCall, internalCallback);
asyncLookupFuture = null;
}
} catch (final RuntimeException e) {
internalCallback.onFailure(e);
asyncLookupFuture = null;
}
m_lookupFuture = asyncLookupFuture;
return asyncLookupFuture;
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class AbstractClientSession method cancelRunningJobs.
protected void cancelRunningJobs() {
// Filter matches all running jobs that have the same client session associated, except the current thread
// and model jobs. Because the current thread is (or should be) a model job, we cannot wait for other
// model threads. They are always cancelled.
IFilter<IFuture<?>> runningJobsFilter = Jobs.newFutureFilterBuilder().andMatch(new SessionFutureFilter(ISession.CURRENT.get())).andMatchNotFuture(IFuture.CURRENT.get()).andMatchNot(ModelJobFutureFilter.INSTANCE).andMatchNotState(JobState.DONE, JobState.REJECTED).toFilter();
// Wait for running jobs to complete before we cancel them
long delay = NumberUtility.nvl(CONFIG.getPropertyValue(JobCompletionDelayOnSessionShutdown.class), 0L);
if (delay > 0L) {
try {
Jobs.getJobManager().awaitDone(runningJobsFilter, delay, TimeUnit.SECONDS);
} catch (TimedOutError e) {
// NOSONAR
// NOP (not all jobs have been finished within the delay)
} catch (ThreadInterruptedError e) {
LOG.warn("Failed to await for running jobs to complete.", e);
}
}
// Cancel remaining jobs and write a warning to the logger
Set<IFuture<?>> runningFutures = Jobs.getJobManager().getFutures(runningJobsFilter);
if (!runningFutures.isEmpty()) {
LOG.warn("Some running client jobs found while stopping the client session; sent a cancellation request to release associated worker threads. [session={}, user={}, jobs={}]", AbstractClientSession.this, getUserId(), runningFutures);
Jobs.getJobManager().cancel(Jobs.newFutureFilterBuilder().andMatchFuture(runningFutures).toFilter(), true);
}
// Now cancel all other model jobs. Because the current thread is a model job, they can never run anyway.
Set<IFuture<?>> runningModelJobs = Jobs.getJobManager().getFutures(Jobs.newFutureFilterBuilder().andMatch(new SessionFutureFilter(ISession.CURRENT.get())).andMatchNotFuture(IFuture.CURRENT.get()).andMatch(ModelJobFutureFilter.INSTANCE).andMatchNotState(JobState.DONE, JobState.REJECTED).toFilter());
if (!runningModelJobs.isEmpty()) {
LOG.info("Cancel running model jobs because the client session was shut down. [session={}, user={}, jobs={}]", AbstractClientSession.this, getUserId(), runningModelJobs);
Jobs.getJobManager().cancel(Jobs.newFutureFilterBuilder().andMatchFuture(runningModelJobs).toFilter(), true);
}
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class MutualExclusionTest method testAcquisition5.
/**
* Task1 acquires the mutex. Then, task2 tries to acquire the mutex and blocks until acquired. Because task2 cannot
* acquire the mutex (hold by task1), it is cancelled hard (interrupted=true). That causes task2 no longer to wait for
* the mutex, meaning that when task1 releases the mutex, task2 does not become the mutex owner.
*/
@Test(timeout = 5_000)
public void testAcquisition5() throws java.lang.InterruptedException {
final ExecutionSemaphore mutex = (ExecutionSemaphore) m_task1.getExecutionSemaphore();
assertEquals(0, mutex.getCompetitorCount());
// Make task1 to acquire the mutex
IPermitAcquiredCallback callbackTask1 = mock(IPermitAcquiredCallback.class);
assertTrue(mutex.compete(m_task1, QueuePosition.HEAD, callbackTask1));
verify(callbackTask1, times(1)).onPermitAcquired();
assertTrue(mutex.isPermitOwner(m_task1));
assertEquals(1, mutex.getCompetitorCount());
// Task2 tries to acquire the mutex, and blocks until acquired
final BlockingCountDownLatch interruptedLatch = new BlockingCountDownLatch(1);
IFuture<Void> future = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
try {
mutex.acquire(m_task2, QueuePosition.TAIL);
} catch (ThreadInterruptedError e) {
interruptedLatch.countDown();
}
}
}, Jobs.newInput().withExceptionHandling(null, false));
JobTestUtil.waitForPermitCompetitors(mutex, 2);
assertTrue(mutex.isPermitOwner(m_task1));
assertEquals(2, mutex.getCompetitorCount());
future.cancel(true);
assertTrue(interruptedLatch.await());
assertTrue(mutex.isPermitOwner(m_task1));
assertEquals(2, mutex.getCompetitorCount());
mutex.release(m_task1);
assertFalse(mutex.isPermitOwner(m_task2));
assertEquals(0, mutex.getCompetitorCount());
}
Aggregations