-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
according to https://rules.sonarsource.com/java/tag/leak/RSPEC-5164/. Now, there no longer is a thread-local stack of AroundClosure instances, but rather a list of them, which can only grow but never shrink. Instead, we now have a thread-local (integer) list index, for every thread being initialised with pointing to the last element. I.e., every thread can unwind by decrementing the index while proceeding, independently of other threads. A positive side effect is that this approach also works for long-lived threads from thread pools, used by executor services. Hence, test Bugs199Tests.testAsyncProceedNestedAroundAdviceThreadPool_gh128, which was previously commented out, has been activated and passes, see #141. I am not sure if this brings @AspectJ style, non-inlined, nested around advice execution functionally on par with native ones, but at least for current scenarios it seems to work. Fixes #288, #141. Signed-off-by: Alexander Kriegisch <[email protected]>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,14 +13,15 @@ | |
|
||
package org.aspectj.runtime.reflect; | ||
|
||
import java.util.Stack; | ||
|
||
import org.aspectj.lang.JoinPoint; | ||
import org.aspectj.lang.ProceedingJoinPoint; | ||
import org.aspectj.lang.Signature; | ||
import org.aspectj.lang.reflect.SourceLocation; | ||
import org.aspectj.runtime.internal.AroundClosure; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
class JoinPointImpl implements ProceedingJoinPoint { | ||
static class StaticPartImpl implements JoinPoint.StaticPart { | ||
String kind; | ||
|
@@ -79,18 +80,6 @@ public EnclosingStaticPartImpl(int count, String kind, Signature signature, Sour | |
} | ||
} | ||
|
||
static class InheritableThreadLocalAroundClosureStack extends InheritableThreadLocal<Stack<AroundClosure>> { | ||
@Override | ||
protected Stack<AroundClosure> initialValue() { | ||
return new Stack<>(); | ||
} | ||
|
||
@Override | ||
protected Stack<AroundClosure> childValue(Stack<AroundClosure> parentValue) { | ||
return (Stack<AroundClosure>) parentValue.clone(); | ||
} | ||
} | ||
|
||
Object _this; | ||
Object target; | ||
Object[] args; | ||
|
@@ -152,23 +141,26 @@ public final String toLongString() { | |
// will either be using arc or arcs but not both. arcs being non-null | ||
// indicates it is in use (even if an empty stack) | ||
private AroundClosure arc = null; | ||
private InheritableThreadLocalAroundClosureStack arcs = null; | ||
private List<AroundClosure> arcs = null; | ||
private final ThreadLocal<Integer> arcIndex = ThreadLocal.withInitial(() -> arcs == null ? -1 : arcs.size() - 1); | ||
|
||
public void set$AroundClosure(AroundClosure arc) { | ||
this.arc = arc; | ||
} | ||
|
||
public void stack$AroundClosure(AroundClosure arc) { | ||
public void stack$AroundClosure(AroundClosure arc) { | ||
// If input parameter arc is null this is the 'unlink' call from AroundClosure | ||
if (arcs == null) { | ||
arcs = new InheritableThreadLocalAroundClosureStack(); | ||
arcs = new ArrayList<>(); | ||
} | ||
if (arc==null) { | ||
this.arcs.get().pop(); | ||
} else { | ||
this.arcs.get().push(arc); | ||
if (arc == null) { | ||
arcIndex.set(arcIndex.get() - 1); | ||
} | ||
else { | ||
this.arcs.add(arc); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
kriegaex
Author
Contributor
|
||
arcIndex.set(arcs.size() - 1); | ||
} | ||
} | ||
} | ||
|
||
public Object proceed() throws Throwable { | ||
// when called from a before advice, but be a no-op | ||
|
@@ -179,19 +171,14 @@ public Object proceed() throws Throwable { | |
return arc.run(arc.getState()); | ||
} | ||
} else { | ||
final AroundClosure ac = arcs.get().peek(); | ||
final AroundClosure ac = arcs.get(arcIndex.get()); | ||
return ac.run(ac.getState()); | ||
} | ||
} | ||
|
||
public Object proceed(Object[] adviceBindings) throws Throwable { | ||
// when called from a before advice, but be a no-op | ||
AroundClosure ac = null; | ||
if (arcs == null) { | ||
ac = arc; | ||
} else { | ||
ac = arcs.get().peek(); | ||
} | ||
AroundClosure ac = arcs == null ? arc : arcs.get(arcIndex.get()); | ||
|
||
if (ac == null) { | ||
return null; | ||
|
I am not very thorough with this code. I am wondering if there would ever be a scenario where this method could be executed simultaneously by two different threads and thereby possibility of a race condition?
Again, it may never happen, just curious.