You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by tj...@apache.org on 2019/06/11 13:12:39 UTC
svn commit: r1861034 -
/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
Author: tjwatson
Date: Tue Jun 11 13:12:39 2019
New Revision: 1861034
URL: http://svn.apache.org/viewvc?rev=1861034&view=rev
Log:
FELIX-6140: possible deadlock in ResolverImpl.EnhancedExecutor.await()
Change await implementation to use a Queue<Future<Void>> to avoid
inaccurate accounting of task count to wait for completion when an
exception is thrown from executor.execute() method. There are scenarios
where the resolver algorithm can take a huge amount of memory resulting
in out of memory errors. If this happens to occur when dispatching a
task to the executor then the count was never decremented.
Modified:
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java?rev=1861034&r1=1861033&r2=1861034&view=diff
==============================================================================
--- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java (original)
+++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java Tue Jun 11 13:12:39 2019
@@ -2440,7 +2440,8 @@ public class ResolverImpl implements Res
}
@Override
- public ResolutionException toException() {
+ public ResolutionException toException()
+ {
return new ReasonException(ReasonException.Reason.UseConstraint, getMessage(), null, getUnresolvedRequirements());
}
}
@@ -2448,8 +2449,8 @@ public class ResolverImpl implements Res
private static class EnhancedExecutor
{
private final Executor executor;
- private final AtomicInteger count = new AtomicInteger();
- private Throwable throwable;
+ private final Queue<Future<Void>> awaiting = new ConcurrentLinkedQueue<Future<Void>>();
+ private final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>();
public EnhancedExecutor(Executor executor)
{
@@ -2458,8 +2459,7 @@ public class ResolverImpl implements Res
public void execute(final Runnable runnable)
{
- count.incrementAndGet();
- executor.execute(new Runnable()
+ FutureTask<Void> task = new FutureTask<Void>(new Runnable()
{
public void run()
{
@@ -2469,59 +2469,63 @@ public class ResolverImpl implements Res
}
catch (Throwable t)
{
- synchronized (count)
- {
- if (throwable == null)
- {
- throwable = t;
- }
- }
- }
- finally
- {
- if (count.decrementAndGet() == 0)
- {
- synchronized (count)
- {
- count.notifyAll();
- }
- }
+ throwable.compareAndSet(null, t);
}
}
- });
+ }, (Void) null);
+ // must have a happens-first to add the task to awaiting
+ awaiting.add(task);
+ try
+ {
+ executor.execute(task);
+ }
+ catch (Throwable t)
+ {
+ // if the task did not get added successfully to the executor we must cancel
+ // the task so we don't await on it
+ task.cancel(false);
+ throwable.compareAndSet(null, t);
+ }
}
public void await()
{
- synchronized (count)
+ Future<Void> awaitTask;
+ while (throwable.get() == null && (awaitTask = awaiting.poll()) != null)
{
- if (count.get() > 0)
+ if (!awaitTask.isDone() && !awaitTask.isCancelled())
{
try
{
- count.wait();
+ awaitTask.get();
+ }
+ catch (CancellationException e)
+ {
+ // ignore; will have throwable set
}
catch (InterruptedException e)
{
throw new IllegalStateException(e);
}
- if (throwable != null)
+ catch (ExecutionException e)
{
- if (throwable instanceof RuntimeException)
- {
- throw (RuntimeException) throwable;
- }
- else if (throwable instanceof Error)
- {
- throw (Error) throwable;
- }
- else
- {
- throw new RuntimeException(throwable);
- }
+ throw new RuntimeException(e.getCause());
}
}
}
+ Throwable t = throwable.get();
+ if (t != null)
+ {
+ if (t instanceof Runnable)
+ {
+ throw (RuntimeException) t;
+ }
+ else if (t instanceof Error)
+ {
+ throw (Error) t;
+ }
+ throw new RuntimeException(t);
+ }
}
}