@@ -39,8 +39,7 @@ public void restoreThreadContext(
39
39
40
40
@ Override
41
41
public ScopeState updateThreadContext (@ NotNull final CoroutineContext coroutineContext ) {
42
- final ScopeState oldScopeState = AgentTracer .get ().newScopeState ();
43
- oldScopeState .fetchFromActive ();
42
+ final ScopeState oldScopeState = AgentTracer .get ().oldScopeState ();
44
43
45
44
final Job coroutine = CoroutineContextHelper .getJob (coroutineContext );
46
45
final ScopeStateCoroutineContextItem contextItem = contextItemPerCoroutine .get (coroutine );
@@ -53,22 +52,20 @@ public ScopeState updateThreadContext(@NotNull final CoroutineContext coroutineC
53
52
54
53
/** If there's a context item for the coroutine then try to close it */
55
54
public void maybeCloseScopeAndCancelContinuation (final Job coroutine , final Job parent ) {
56
- final ScopeStateCoroutineContextItem contextItem = contextItemPerCoroutine .get (coroutine );
55
+ final ScopeStateCoroutineContextItem contextItem = contextItemPerCoroutine .remove (coroutine );
57
56
if (contextItem != null ) {
58
57
ScopeState currentThreadScopeState = null ;
59
58
if (parent != null ) {
60
59
final ScopeStateCoroutineContextItem parentItem = contextItemPerCoroutine .get (parent );
61
60
if (parentItem != null ) {
62
- currentThreadScopeState = parentItem .getScopeState ();
61
+ currentThreadScopeState = parentItem .maybeCopyScopeState ();
63
62
}
64
63
}
65
64
if (currentThreadScopeState == null ) {
66
- currentThreadScopeState = AgentTracer .get ().newScopeState ();
67
- currentThreadScopeState .fetchFromActive ();
65
+ currentThreadScopeState = AgentTracer .get ().oldScopeState ();
68
66
}
69
67
70
68
contextItem .maybeCloseScopeAndCancelContinuation ();
71
- contextItemPerCoroutine .remove (coroutine );
72
69
73
70
currentThreadScopeState .activate ();
74
71
}
@@ -111,16 +108,23 @@ public static class ScopeStateCoroutineContextItem {
111
108
@ Nullable private AgentScope .Continuation continuation ;
112
109
@ Nullable private AgentScope continuationScope ;
113
110
private boolean isInitialized = false ;
111
+ private volatile Thread activatedOn ;
114
112
115
113
public ScopeStateCoroutineContextItem () {
116
114
coroutineScopeState = AgentTracer .get ().newScopeState ();
117
115
}
118
116
119
- public ScopeState getScopeState () {
120
- return coroutineScopeState ;
117
+ public ScopeState maybeCopyScopeState () {
118
+ // take defensive copy of scope stack if on different thread
119
+ if (activatedOn != null && activatedOn != Thread .currentThread ()) {
120
+ return coroutineScopeState .copy ();
121
+ } else {
122
+ return coroutineScopeState ;
123
+ }
121
124
}
122
125
123
126
public void activate () {
127
+ activatedOn = Thread .currentThread ();
124
128
coroutineScopeState .activate ();
125
129
126
130
if (continuation != null && continuationScope == null ) {
@@ -144,6 +148,7 @@ public void maybeInitialize() {
144
148
* scope and cancels the continuation.
145
149
*/
146
150
public void maybeCloseScopeAndCancelContinuation () {
151
+ // only temporary activation, will be replaced by another activate in caller
147
152
coroutineScopeState .activate ();
148
153
149
154
if (continuationScope != null ) {
0 commit comments