Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@
public interface ContextListener {

/**
* Notifies that the given context has been attached to the current execution unit.
* Notifies that the context has been updated for the current execution unit.
*
* @param context the attached context.
* @param before the context before.
* @param after the context after.
*/
default void onAttach(Context context) {}

/**
* Notifies that the given context has been detached from the current execution unit.
*
* @param context the detached context.
*/
default void onDetach(Context context) {}
default void onUpdate(Context before, Context after) {}

/**
* Notifies that the given context has been captured by a continuation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
final class ThreadLocalContextManager implements ContextManager {
static final ThreadLocalContextManager INSTANCE = new ThreadLocalContextManager();

private static final NoopContextContinuation ROOT_CONTINUATION =
new NoopContextContinuation(Context.root());

private static final ThreadLocal<ContextHolder> CONTEXT_HOLDER =
ThreadLocal.withInitial(ContextHolder::new);

private static final NoopContextContinuation ROOT_CONTINUATION =
new NoopContextContinuation(Context.root());

private final Object listenersWriteLock = new Object();
volatile ContextListener[] listeners = {};

Expand All @@ -40,16 +40,12 @@ ContextScope doAttach(Context context, @Nullable ContextContinuationImpl continu
return context.asScope(); // convert to scope without attaching
}

ContextListener[] ls = listeners;
notifyDetach(beforeAttach, ls);
holder.current = context;
notifyAttach(context, ls);
notifyUpdate(listeners, beforeAttach, context);

if (continuation == null) {
return new ContextScopeImpl(context, holder, beforeAttach);
} else {
return new ResumedScopeImpl(context, holder, beforeAttach, continuation);
}
return continuation == null
? new ContextScopeImpl(context, holder, beforeAttach)
: new ResumedScopeImpl(context, holder, beforeAttach, continuation);
}

@Override
Expand All @@ -61,21 +57,15 @@ public Context swap(Context context) {
return beforeSwap;
}

ContextListener[] ls = listeners;
notifyDetach(beforeSwap, ls);
holder.current = context;
notifyAttach(context, ls);
notifyUpdate(listeners, beforeSwap, context);

return beforeSwap;
}

@Override
public ContextContinuation capture(Context context) {
if (context == Context.root()) {
return ROOT_CONTINUATION;
} else {
return new ContextContinuationImpl(context);
}
return context == Context.root() ? ROOT_CONTINUATION : new ContextContinuationImpl(context);
}

@Override
Expand All @@ -99,31 +89,16 @@ void clearListeners() {
}
}

static void notifyAttach(Context context, ContextListener[] listeners) {
if (context == Context.root()) {
return; // don't emit attach events for the default "no context" case
}
for (ContextListener l : listeners) {
try {
l.onAttach(context);
} catch (Throwable ignore) {
}
}
}

static void notifyDetach(Context context, ContextListener[] listeners) {
if (context == Context.root()) {
return; // don't emit detach events for the default "no context" case
}
static void notifyUpdate(ContextListener[] listeners, Context before, Context after) {
for (ContextListener l : listeners) {
try {
l.onDetach(context);
l.onUpdate(before, after);
} catch (Throwable ignore) {
}
}
}

static void notifyCapture(Context context, ContextListener[] listeners) {
static void notifyCapture(ContextListener[] listeners, Context context) {
// only called for non-empty continuations
for (ContextListener l : listeners) {
try {
Expand All @@ -133,7 +108,7 @@ static void notifyCapture(Context context, ContextListener[] listeners) {
}
}

static void notifyRelease(Context context, ContextListener[] listeners) {
static void notifyRelease(ContextListener[] listeners, Context context) {
// only called for non-empty continuations
for (ContextListener l : listeners) {
try {
Expand Down Expand Up @@ -166,10 +141,8 @@ public final Context context() {
public void close() {
// check for out-of-order close to avoid corrupting the current state
if (!closed && context == holder.current) {
ContextListener[] ls = INSTANCE.listeners;
notifyDetach(context, ls);
holder.current = beforeAttach;
notifyAttach(beforeAttach, ls);
notifyUpdate(INSTANCE.listeners, context, beforeAttach);
closed = true;
}
}
Expand Down Expand Up @@ -232,7 +205,7 @@ private static final class ContextContinuationImpl implements ContextContinuatio

ContextContinuationImpl(Context context) {
this.context = context;
notifyCapture(context, INSTANCE.listeners);
notifyCapture(INSTANCE.listeners, context);
}

@Override
Expand Down Expand Up @@ -270,7 +243,7 @@ public void release() {
while (current == 0) {
// no outstanding resumes and hold has been removed
if (COUNT.compareAndSet(this, current, RELEASED)) {
notifyRelease(context, INSTANCE.listeners);
notifyRelease(INSTANCE.listeners, context);
return;
}
current = count;
Expand All @@ -280,7 +253,7 @@ public void release() {
void releaseOnScopeClose() {
if (COUNT.compareAndSet(this, 1, RELEASED)) {
// fast path: only one resume of the continuation (no hold)
notifyRelease(context, INSTANCE.listeners);
notifyRelease(INSTANCE.listeners, context);
} else if (COUNT.decrementAndGet(this) == 0) {
// slow path: multiple resumes, all scopes now closed (no hold)
release();
Expand Down
Loading