Skip to content

Commit b6c508b

Browse files
committed
Save/restore contexts for custom notifiers
1 parent e053a3f commit b6c508b

File tree

12 files changed

+61
-9
lines changed

12 files changed

+61
-9
lines changed

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ private struct RuntimeAsyncAwaitState
171171
public INotifyCompletion? Notifier;
172172
public IValueTaskSourceNotifier? ValueTaskSourceNotifier;
173173
public Task? TaskNotifier;
174+
175+
public ExecutionContext? ExecutionContext;
176+
public SynchronizationContext? SynchronizationContext;
177+
178+
public void CaptureContexts()
179+
{
180+
Thread curThread = Thread.CurrentThreadAssumedInitialized;
181+
ExecutionContext = curThread._executionContext;
182+
SynchronizationContext = curThread._synchronizationContext;
183+
}
174184
}
175185

176186
[ThreadStatic]
@@ -240,6 +250,7 @@ private static void TransparentAwait(object o)
240250
state.ValueTaskSourceNotifier = (IValueTaskSourceNotifier)o;
241251
}
242252

253+
state.CaptureContexts();
243254
AsyncSuspend(sentinelContinuation);
244255
}
245256

@@ -541,6 +552,8 @@ public static void HandleSuspended<T, TOps>(T task) where T : Task, ITaskComplet
541552
{
542553
ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState;
543554

555+
RestoreContextsOnSuspension(false, state.ExecutionContext, state.SynchronizationContext);
556+
544557
ICriticalNotifyCompletion? critNotifier = state.CriticalNotifier;
545558
INotifyCompletion? notifier = state.Notifier;
546559
IValueTaskSourceNotifier? vtsNotifier = state.ValueTaskSourceNotifier;
@@ -550,6 +563,8 @@ public static void HandleSuspended<T, TOps>(T task) where T : Task, ITaskComplet
550563
state.Notifier = null;
551564
state.ValueTaskSourceNotifier = null;
552565
state.TaskNotifier = null;
566+
state.ExecutionContext = null;
567+
state.SynchronizationContext = null;
553568

554569
Continuation sentinelContinuation = state.SentinelContinuation!;
555570
Continuation headContinuation = sentinelContinuation.Next!;
@@ -794,6 +809,28 @@ private static void RestoreContexts(bool resumed, ExecutionContext? previousExec
794809
}
795810
}
796811

812+
// Restore contexts onto current Thread as we unwind during suspension. We control the code that runs
813+
// during suspension and we do not need to raise ExecutionContext notifications -- we know that it is
814+
// not going to be accessed and that DispatchContinuations will return it back to the leaf's context
815+
// before calling user code, and restore the original contexts with appropriate notifications before
816+
// returning.
817+
private static void RestoreContextsOnSuspension(bool resumed, ExecutionContext? previousExecCtx, SynchronizationContext? previousSyncCtx)
818+
{
819+
if (!resumed)
820+
{
821+
Thread thread = Thread.CurrentThreadAssumedInitialized;
822+
if (previousSyncCtx != thread._synchronizationContext)
823+
{
824+
thread._synchronizationContext = previousSyncCtx;
825+
}
826+
827+
if (previousExecCtx != thread._executionContext)
828+
{
829+
thread._executionContext = previousExecCtx;
830+
}
831+
}
832+
}
833+
797834
private static void CaptureContinuationContext(ref object continuationContext, ref ContinuationFlags flags)
798835
{
799836
SynchronizationContext? syncCtx = Thread.CurrentThreadAssumedInitialized._synchronizationContext;

src/coreclr/inc/corinfo.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,13 +1754,18 @@ struct CORINFO_ASYNC_INFO
17541754
CORINFO_FIELD_HANDLE continuationStateFldHnd;
17551755
// 'Flags' field
17561756
CORINFO_FIELD_HANDLE continuationFlagsFldHnd;
1757-
// Method handle for AsyncHelpers.CaptureExecutionContext
1757+
// Method handle for AsyncHelpers.CaptureExecutionContext, used during suspension
17581758
CORINFO_METHOD_HANDLE captureExecutionContextMethHnd;
1759-
// Method handle for AsyncHelpers.RestoreExecutionContext
1759+
// Method handle for AsyncHelpers.RestoreExecutionContext, used during resumption
17601760
CORINFO_METHOD_HANDLE restoreExecutionContextMethHnd;
1761+
// Method handle for AsyncHelpers.CaptureContinuationContext, used during suspension
17611762
CORINFO_METHOD_HANDLE captureContinuationContextMethHnd;
1763+
// Method handle for AsyncHelpers.CaptureContexts, used at the beginning of async methods
17621764
CORINFO_METHOD_HANDLE captureContextsMethHnd;
1765+
// Method handle for AsyncHelpers.RestoreContexts, used before normal returns from async methods
17631766
CORINFO_METHOD_HANDLE restoreContextsMethHnd;
1767+
// Method handle for AsyncHelpers.RestoreContextsOnSuspension, used before suspending in async methods
1768+
CORINFO_METHOD_HANDLE restoreContextsOnSuspensionMethHnd;
17641769
};
17651770

17661771
// Flags passed from JIT to runtime.

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737

3838
#include <minipal/guid.h>
3939

40-
constexpr GUID JITEEVersionIdentifier = { /* 2d5333ab-eda7-4fd9-afc9-4a073dc0f7ec */
41-
0x2d5333ab,
42-
0xeda7,
43-
0x4fd9,
44-
{0xaf, 0xc9, 0x4a, 0x07, 0x3d, 0xc0, 0xf7, 0xec}
40+
constexpr GUID JITEEVersionIdentifier = { /* c3e8a087-931a-4aa4-a311-13e6736e509a */
41+
0xc3e8a087,
42+
0x931a,
43+
0x4aa4,
44+
{0xa3, 0x11, 0x13, 0xe6, 0x73, 0x6e, 0x50, 0x9a}
4545
};
4646

4747
#endif // JIT_EE_VERSIONING_GUID_H

src/coreclr/jit/async.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1707,7 +1707,8 @@ void AsyncTransformation::RestoreContexts(BasicBlock* block, GenTreeCall* call,
17071707
GenTree* resumedPlaceholder = m_comp->gtNewIconNode(0);
17081708
GenTree* execContextPlaceholder = m_comp->gtNewNull();
17091709
GenTree* syncContextPlaceholder = m_comp->gtNewNull();
1710-
GenTreeCall* restoreCall = m_comp->gtNewCallNode(CT_USER_FUNC, m_asyncInfo->restoreContextsMethHnd, TYP_VOID);
1710+
GenTreeCall* restoreCall =
1711+
m_comp->gtNewCallNode(CT_USER_FUNC, m_asyncInfo->restoreContextsOnSuspensionMethHnd, TYP_VOID);
17111712

17121713
restoreCall->gtArgs.PushFront(m_comp, NewCallArg::Primitive(syncContextPlaceholder));
17131714
restoreCall->gtArgs.PushFront(m_comp, NewCallArg::Primitive(execContextPlaceholder));

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,7 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut)
34023402
pAsyncInfoOut.captureContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("CaptureContinuationContext"u8, null));
34033403
pAsyncInfoOut.captureContextsMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("CaptureContexts"u8, null));
34043404
pAsyncInfoOut.restoreContextsMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("RestoreContexts"u8, null));
3405+
pAsyncInfoOut.restoreContextsOnSuspensionMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("RestoreContextsOnSuspension"u8, null));
34053406
}
34063407

34073408
private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize)

src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,7 @@ public unsafe struct CORINFO_ASYNC_INFO
905905
public CORINFO_METHOD_STRUCT_* captureContinuationContextMethHnd;
906906
public CORINFO_METHOD_STRUCT_* captureContextsMethHnd;
907907
public CORINFO_METHOD_STRUCT_* restoreContextsMethHnd;
908+
public CORINFO_METHOD_STRUCT_* restoreContextsOnSuspensionMethHnd;
908909
}
909910

910911
// Flags passed from JIT to runtime.

src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ private void ImportCall(ILOpcode opcode, int token)
471471
_dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("CaptureExecutionContext"u8, null)), asyncReason);
472472
_dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("RestoreExecutionContext"u8, null)), asyncReason);
473473
_dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("CaptureContinuationContext"u8, null)), asyncReason);
474+
_dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("RestoreContextsOnSuspension"u8, null)), asyncReason);
474475
}
475476

476477
// If this is the task await pattern, we're actually going to call the variant

src/coreclr/tools/superpmi/superpmi-shared/agnostic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ struct Agnostic_CORINFO_ASYNC_INFO
205205
DWORDLONG captureContinuationContextMethHnd;
206206
DWORDLONG captureContextsMethHnd;
207207
DWORDLONG restoreContextsMethHnd;
208+
DWORDLONG restoreContextsOnSuspensionMethHnd;
208209
};
209210

210211
struct Agnostic_GetOSRInfo

src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4462,6 +4462,7 @@ void MethodContext::recGetAsyncInfo(const CORINFO_ASYNC_INFO* pAsyncInfo)
44624462
value.captureContinuationContextMethHnd = CastHandle(pAsyncInfo->captureContinuationContextMethHnd);
44634463
value.captureContextsMethHnd = CastHandle(pAsyncInfo->captureContextsMethHnd);
44644464
value.restoreContextsMethHnd = CastHandle(pAsyncInfo->restoreContextsMethHnd);
4465+
value.restoreContextsOnSuspensionMethHnd = CastHandle(pAsyncInfo->restoreContextsOnSuspensionMethHnd);
44654466

44664467
GetAsyncInfo->Add(0, value);
44674468
DEBUG_REC(dmpGetAsyncInfo(0, value));
@@ -4486,6 +4487,7 @@ void MethodContext::repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut)
44864487
pAsyncInfoOut->captureContinuationContextMethHnd = (CORINFO_METHOD_HANDLE)value.captureContinuationContextMethHnd;
44874488
pAsyncInfoOut->captureContextsMethHnd = (CORINFO_METHOD_HANDLE)value.captureContextsMethHnd;
44884489
pAsyncInfoOut->restoreContextsMethHnd = (CORINFO_METHOD_HANDLE)value.restoreContextsMethHnd;
4490+
pAsyncInfoOut->restoreContextsOnSuspensionMethHnd = (CORINFO_METHOD_HANDLE)value.restoreContextsOnSuspensionMethHnd;
44894491
DEBUG_REP(dmpGetAsyncInfo(0, value));
44904492
}
44914493

src/coreclr/vm/corelib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ DEFINE_METHOD(ASYNC_HELPERS, RESTORE_EXECUTION_CONTEXT, RestoreExecutionCon
739739
DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTINUATION_CONTEXT, CaptureContinuationContext, NoSig)
740740
DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTEXTS, CaptureContexts, NoSig)
741741
DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS, RestoreContexts, NoSig)
742+
DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS_ON_SUSPENSION, RestoreContextsOnSuspension, NoSig)
742743
DEFINE_METHOD(ASYNC_HELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, NoSig)
743744

744745
#ifdef TARGET_BROWSER

0 commit comments

Comments
 (0)