From fdf9a733014de746b71c07e140a056bd793993ff Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Wed, 30 Sep 2026 15:08:46 -0500 Subject: [PATCH 1/5] [wasi] Enable EventPipe (FEATURE_PERFTRACING) for CoreCLR WASI Enable FEATURE_EVENT_TRACE/FEATURE_PERFTRACING for CoreCLR WASI using threadless EventPipe, matching browser CoreCLR, and turn FeaturePerfTracing back on in CoreLib. - Build the TCP flavor of the diagnostic server PAL (WASI has no AF_UNIX) and disable all listen/connect ports until a WASI transport is validated. - ep_rt_queue_job returns false instead of hitting EP_UNREACHABLE when the host has no job queue; ep_session_start_streaming drops the job's session reference in that case. Streaming sessions are flushed on disable. - Exclude the out-of-process EventPipeListener test harness on WASI, as on browser. Fixes EventSource activity-id tracking on WASI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- eng/native.wasm.targets | 10 +++++----- src/coreclr/CMakeLists.txt | 4 ---- src/coreclr/clr.featuredefines.props | 12 ------------ src/coreclr/debug/debug-pal/CMakeLists.txt | 7 +------ src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h | 3 ++- .../tests/BasicEventSourceTest/TestsWrite.cs | 2 +- .../tests/BasicEventSourceTest/TestsWriteEvent.cs | 2 +- src/native/eventpipe/ep-session.c | 6 +++++- 8 files changed, 15 insertions(+), 31 deletions(-) diff --git a/eng/native.wasm.targets b/eng/native.wasm.targets index 734349ba2f1d34..f8593ec4c87e1d 100644 --- a/eng/native.wasm.targets +++ b/eng/native.wasm.targets @@ -82,13 +82,13 @@ - + + + diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 619f7ae0426f52..fac6af9914e22a 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -39,10 +39,6 @@ if(CLR_CMAKE_TARGET_WASI) add_compile_definitions(_WASI_EMULATED_PROCESS_CLOCKS) add_compile_definitions(_WASI_EMULATED_MMAN) add_compile_definitions(_WASI_EMULATED_GETPID) - # EventPipe / diag-server PAL require sockets we have not validated - # for the WASI bring-up; revisit once corerun.wasm runs. - set(FEATURE_EVENT_TRACE 0) - set(FEATURE_PERFTRACING 0) include_directories(BEFORE SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/pal/src/include/pal/wasi) # Cross-compile try_run() answers — wasm32 binaries cannot execute on # the build host, so pre-seed the cache. diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props index 4ce076aabd2fc0..d7e767113eb060 100644 --- a/src/coreclr/clr.featuredefines.props +++ b/src/coreclr/clr.featuredefines.props @@ -28,18 +28,6 @@ false - - - false - - true true diff --git a/src/coreclr/debug/debug-pal/CMakeLists.txt b/src/coreclr/debug/debug-pal/CMakeLists.txt index 59b18e2c91ddb8..d7a233790e7316 100644 --- a/src/coreclr/debug/debug-pal/CMakeLists.txt +++ b/src/coreclr/debug/debug-pal/CMakeLists.txt @@ -27,12 +27,7 @@ if(CLR_CMAKE_HOST_WIN32) endif(CLR_CMAKE_HOST_WIN32) if(CLR_CMAKE_HOST_UNIX) - if (NOT CLR_CMAKE_TARGET_WASI) - # ds-ipc-pal-socket.c needs UNIX/TCP sockets; re-enable once - # WASI PERFTRACING is wired. Tracked by https://github.com/dotnet/runtime/issues/130383 - - set(DEBUG_PAL_REFEREENCE_DIAGNOSTICSERVER ON) - endif() + set(DEBUG_PAL_REFEREENCE_DIAGNOSTICSERVER ON) add_definitions(-DPAL_IMPLEMENTATION) add_definitions(-D_POSIX_C_SOURCE=200809L) diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index d54e561cbf9871..2dd6d600c1a293 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -1112,7 +1112,8 @@ ep_rt_queue_job ( SystemJS_DiagnosticServerQueueJob (cb, params); return true; #else - EP_UNREACHABLE ("Not implemented on this platform"); + // No host event loop to run jobs on (e.g. WASI). Callers handle the failure; streaming sessions + // are flushed when they are disabled. return false; #endif } diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs index b5d71dacd83346..aecf69e0ca1846 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs @@ -30,7 +30,7 @@ public static TheoryData GetListeners() { TheoryData data = new TheoryData(); - if (PlatformDetection.IsNetCore && PlatformDetection.IsNotAndroid && PlatformDetection.IsNotBrowser && + if (PlatformDetection.IsNetCore && PlatformDetection.IsNotAndroid && PlatformDetection.IsNotBrowser && PlatformDetection.IsNotWasi && (PlatformDetection.IsNotMonoRuntime || PlatformDetection.IsMacCatalyst)) { data.Add(new EventPipeListener()); diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs index ae0d1602e8407c..079d623bb16b1c 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs @@ -30,7 +30,7 @@ public static TheoryData GetListenerConfigurations() public static TheoryData GetListeners() { TheoryData data = new TheoryData(); - if (PlatformDetection.IsNetCore && PlatformDetection.IsNotAndroid && PlatformDetection.IsNotBrowser && + if (PlatformDetection.IsNetCore && PlatformDetection.IsNotAndroid && PlatformDetection.IsNotBrowser && PlatformDetection.IsNotWasi && (PlatformDetection.IsNotMonoRuntime || PlatformDetection.IsMacCatalyst)) { data.Add(new EventPipeListener()); diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c index 09c6a12b41f104..44cd721f0f775b 100644 --- a/src/native/eventpipe/ep-session.c +++ b/src/native/eventpipe/ep-session.c @@ -190,7 +190,11 @@ session_create_streaming_thread (EventPipeSession *session) #else ep_session_inc_ref (session); ep_rt_volatile_store_uint32_t (&session->started, 1); - ep_rt_queue_job ((void *)streaming_loop_tick, (void *)session); + if (!ep_rt_queue_job ((void *)streaming_loop_tick, (void *)session)) { + // The host can't run jobs, so drop the job's reference. Buffered events are + // flushed when the session is disabled. + ep_rt_atomic_dec_uint32_t (&session->ref_count); + } #endif } From 5f33b10636488a474a87bfa63b64b948922c0082 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 1 Oct 2026 15:49:45 -0500 Subject: [PATCH 2/5] [wasi] Pump EventPipe jobs from the WASI event loop Browser runs EventPipe jobs (session streaming, diagnostic server) from a JS setTimeout loop. WASI has no host event loop, so keep the jobs on a native list and drain it from managed WasiEventLoop via two QCalls, re-polling every 100ms with Task.Delay (which blocks in wasi:io/poll rather than spinning). Jobs only run while the event loop is pumped; otherwise streaming sessions still flush when they are disabled. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../vm/eventing/eventpipe/ep-rt-coreclr.h | 7 +- src/coreclr/vm/eventpipeinternal.cpp | 77 +++++++++++++++++++ src/coreclr/vm/eventpipeinternal.h | 6 ++ src/coreclr/vm/qcallentrypoints.cpp | 4 + .../System.Private.CoreLib.Shared.projitems | 3 + .../System/Threading/Wasi/WasiEventLoop.cs | 6 ++ .../Threading/Wasi/WasiEventPipeJobs.cs | 61 +++++++++++++++ 7 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventPipeJobs.cs diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index 2dd6d600c1a293..3ff0a0b796e62e 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -1094,6 +1094,9 @@ ep_rt_thread_create ( #ifdef HOST_BROWSER #include "wasm/entrypoints.h" typedef size_t (*ep_rt_job_cb_t)(void *data); +#elif defined(TARGET_WASI) +// Queues a job on the native list drained by the managed WASI event loop (see eventpipeinternal.cpp). +bool ep_rt_coreclr_wasi_queue_job (size_t (*cb)(void *data), void *data); #endif static @@ -1111,8 +1114,10 @@ ep_rt_queue_job ( if (!cb (params)) SystemJS_DiagnosticServerQueueJob (cb, params); return true; +#elif defined(TARGET_WASI) + return ep_rt_coreclr_wasi_queue_job ((size_t (*)(void *))job_func, params); #else - // No host event loop to run jobs on (e.g. WASI). Callers handle the failure; streaming sessions + // No host event loop to run jobs on. Callers handle the failure; streaming sessions // are flushed when they are disabled. return false; #endif diff --git a/src/coreclr/vm/eventpipeinternal.cpp b/src/coreclr/vm/eventpipeinternal.cpp index 5a2dc9933c800c..cf42d83d18dd5b 100644 --- a/src/coreclr/vm/eventpipeinternal.cpp +++ b/src/coreclr/vm/eventpipeinternal.cpp @@ -296,4 +296,81 @@ extern "C" BOOL QCALLTYPE EventPipeInternal_WaitForSessionSignal(UINT64 sessionI return result; } +#if defined(TARGET_WASI) && defined(PERFTRACING_DISABLE_THREADS) +// WASI has no host event loop to schedule EventPipe jobs (session streaming, diagnostic server) on, +// so they are kept on this list and run by the managed WasiEventLoop (WasiEventPipeJobs.cs). +// A job returns non-zero when it is done; otherwise it stays queued and runs again on the next pump. +// Single-threaded by construction, so no locking. +struct WasiEventPipeJob +{ + size_t (*Callback)(void *data); + void *Data; + WasiEventPipeJob *Next; +}; + +static WasiEventPipeJob *s_wasiJobsHead = nullptr; +static WasiEventPipeJob *s_wasiJobsTail = nullptr; + +static void WasiAppendJob(WasiEventPipeJob *job) +{ + job->Next = nullptr; + if (s_wasiJobsTail != nullptr) + s_wasiJobsTail->Next = job; + else + s_wasiJobsHead = job; + s_wasiJobsTail = job; +} + +bool ep_rt_coreclr_wasi_queue_job(size_t (*cb)(void *data), void *data) +{ + _ASSERTE(cb != nullptr); + WasiEventPipeJob *job = new (nothrow) WasiEventPipeJob(); + if (job == nullptr) + return false; + + job->Callback = cb; + job->Data = data; + WasiAppendJob(job); + return true; +} + +extern "C" CLR_BOOL QCALLTYPE EventPipeInternal_WasiHasPendingJobs(QCallExceptionStatus* qcallError) +{ + QCALL_CONTRACT; + + CLR_BOOL pending = FALSE; + + BEGIN_QCALL; + + pending = s_wasiJobsHead != nullptr ? TRUE : FALSE; + + END_QCALL; + return pending; +} + +extern "C" void QCALLTYPE EventPipeInternal_WasiRunJobs(QCallExceptionStatus* qcallError) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + + // Detach the current list so jobs queued while running are picked up on the next pump. + WasiEventPipeJob *job = s_wasiJobsHead; + s_wasiJobsHead = nullptr; + s_wasiJobsTail = nullptr; + + while (job != nullptr) + { + WasiEventPipeJob *next = job->Next; + if (job->Callback(job->Data) != 0) + delete job; + else + WasiAppendJob(job); + job = next; + } + + END_QCALL; +} +#endif // TARGET_WASI && PERFTRACING_DISABLE_THREADS + #endif // FEATURE_PERFTRACING diff --git a/src/coreclr/vm/eventpipeinternal.h b/src/coreclr/vm/eventpipeinternal.h index 09cb9acedaca28..cbfd0f040a43dc 100644 --- a/src/coreclr/vm/eventpipeinternal.h +++ b/src/coreclr/vm/eventpipeinternal.h @@ -104,6 +104,12 @@ extern "C" BOOL QCALLTYPE EventPipeInternal_WaitForSessionSignal( INT32 timeoutMs, QCallExceptionStatus* qcallError); +#if defined(TARGET_WASI) && defined(PERFTRACING_DISABLE_THREADS) +extern "C" CLR_BOOL QCALLTYPE EventPipeInternal_WasiHasPendingJobs(QCallExceptionStatus* qcallError); + +extern "C" void QCALLTYPE EventPipeInternal_WasiRunJobs(QCallExceptionStatus* qcallError); +#endif // TARGET_WASI && PERFTRACING_DISABLE_THREADS + #endif // FEATURE_PERFTRACING #endif // __EVENTPIPEINTERNAL_H__ diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 6582a1ccf5e9f4..41e423998dfa4b 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -489,6 +489,10 @@ static const Entry s_QCall[] = DllImportEntry(EventPipeInternal_GetNextEvent) DllImportEntry(EventPipeInternal_SignalSession) DllImportEntry(EventPipeInternal_WaitForSessionSignal) +#if defined(TARGET_WASI) && defined(PERFTRACING_DISABLE_THREADS) + DllImportEntry(EventPipeInternal_WasiHasPendingJobs) + DllImportEntry(EventPipeInternal_WasiRunJobs) +#endif // TARGET_WASI && PERFTRACING_DISABLE_THREADS #endif // FEATURE_PERFTRACING #if defined(TARGET_UNIX) DllImportEntry(FreeEnvironmentStringsW) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index abe0dcc14a7c0f..a8abf0ac747810 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -2993,6 +2993,9 @@ + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index 0dba1ec0041502..50550b6a5af23e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -58,6 +58,9 @@ internal static T PollWasiEventLoopUntilResolved(Task mainTask) { ThreadPoolWorkQueue.Dispatch(); WasiFinalizerScheduler.DrainIfPending(); +#if FEATURE_PERFTRACING && CORECLR + WasiEventPipeJobs.EnsurePumpIfPending(); +#endif } } finally @@ -80,6 +83,9 @@ internal static void PollWasiEventLoopUntilResolvedVoid(Task mainTask) { ThreadPoolWorkQueue.Dispatch(); WasiFinalizerScheduler.DrainIfPending(); +#if FEATURE_PERFTRACING && CORECLR + WasiEventPipeJobs.EnsurePumpIfPending(); +#endif } } finally diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventPipeJobs.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventPipeJobs.cs new file mode 100644 index 00000000000000..01aee8d405d8f1 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventPipeJobs.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace System.Threading +{ + // Runs the native EventPipe jobs (session streaming, diagnostic server) that browser schedules with + // setTimeout. WASI has no host event loop, so the native side keeps a job list and WasiEventLoop + // starts this pump when it sees pending jobs. Jobs only run while the event loop is being pumped. + internal static partial class WasiEventPipeJobs + { + // Matches the browser re-schedule interval for unfinished jobs. + private const int PumpIntervalMs = 100; + + private static bool s_pumpRunning; + + [ErrorHandler(typeof(QCallExceptionStatusMarshaller), ErrorLocation.HiddenLastParameter)] + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "EventPipeInternal_WasiHasPendingJobs")] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool HasPendingJobs(); + + [ErrorHandler(typeof(QCallExceptionStatusMarshaller), ErrorLocation.HiddenLastParameter)] + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "EventPipeInternal_WasiRunJobs")] + private static partial void RunJobs(); + + internal static void EnsurePumpIfPending() + { + if (s_pumpRunning || !HasPendingJobs()) + { + return; + } + + s_pumpRunning = true; + _ = PumpAsync(); + } + + private static async Task PumpAsync() + { + try + { + while (true) + { + RunJobs(); + if (!HasPendingJobs()) + { + break; + } + + await Task.Delay(PumpIntervalMs).ConfigureAwait(false); + } + } + finally + { + s_pumpRunning = false; + } + } + } +} From 7940073ee903b78c5d6037ed026ccdce132244b6 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 1 Oct 2026 16:14:22 -0500 Subject: [PATCH 3/5] [wasi] Finish EventPipe traces at shutdown and address review feedback - Run queued WASI EventPipe jobs once from ep_rt_shutdown. A queued streaming job holds a session reference, and the event loop no longer runs after shutdown, so the session was never freed and its trace never got the end-of-stream tag. - Start the job pump before ThreadPoolWorkQueue.Dispatch, which can block in wasi:io/poll, and skip it in multithreaded builds where the pump is not compiled. - Restore EP_UNREACHABLE for single-threaded CoreCLR hosts other than browser and WASI. - On a streaming write failure, keep the job so the next tick releases the session reference instead of leaking it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../vm/eventing/eventpipe/ep-rt-coreclr.h | 18 +++++++++++++----- src/coreclr/vm/eventpipeinternal.cpp | 15 ++++++++++----- .../src/System/Threading/Wasi/WasiEventLoop.cs | 14 ++++++++------ src/native/eventpipe/ep-session.c | 6 +++--- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index 3ff0a0b796e62e..2372cff7abc808 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -314,12 +314,24 @@ ep_rt_init_finish (void) STATIC_CONTRACT_NOTHROW; } +#if defined(TARGET_WASI) && defined(PERFTRACING_DISABLE_THREADS) +// WASI has no host event loop, so jobs are kept on a native list that the managed +// WASI event loop drains (see eventpipeinternal.cpp). +bool ep_rt_coreclr_wasi_queue_job (size_t (*cb)(void *data), void *data); +void ep_rt_coreclr_wasi_run_jobs (void); +#endif + static inline void ep_rt_shutdown (void) { STATIC_CONTRACT_NOTHROW; +#if defined(TARGET_WASI) && defined(PERFTRACING_DISABLE_THREADS) + // The event loop no longer runs, so run the queued jobs once to let the now-disabled streaming + // sessions release their references; freeing a session ends its trace file. + ep_rt_coreclr_wasi_run_jobs (); +#endif } static @@ -1094,9 +1106,6 @@ ep_rt_thread_create ( #ifdef HOST_BROWSER #include "wasm/entrypoints.h" typedef size_t (*ep_rt_job_cb_t)(void *data); -#elif defined(TARGET_WASI) -// Queues a job on the native list drained by the managed WASI event loop (see eventpipeinternal.cpp). -bool ep_rt_coreclr_wasi_queue_job (size_t (*cb)(void *data), void *data); #endif static @@ -1117,8 +1126,7 @@ ep_rt_queue_job ( #elif defined(TARGET_WASI) return ep_rt_coreclr_wasi_queue_job ((size_t (*)(void *))job_func, params); #else - // No host event loop to run jobs on. Callers handle the failure; streaming sessions - // are flushed when they are disabled. + EP_UNREACHABLE ("Not implemented on this platform"); return false; #endif } diff --git a/src/coreclr/vm/eventpipeinternal.cpp b/src/coreclr/vm/eventpipeinternal.cpp index cf42d83d18dd5b..72eafc9f1e9cab 100644 --- a/src/coreclr/vm/eventpipeinternal.cpp +++ b/src/coreclr/vm/eventpipeinternal.cpp @@ -348,12 +348,8 @@ extern "C" CLR_BOOL QCALLTYPE EventPipeInternal_WasiHasPendingJobs(QCallExceptio return pending; } -extern "C" void QCALLTYPE EventPipeInternal_WasiRunJobs(QCallExceptionStatus* qcallError) +void ep_rt_coreclr_wasi_run_jobs() { - QCALL_CONTRACT; - - BEGIN_QCALL; - // Detach the current list so jobs queued while running are picked up on the next pump. WasiEventPipeJob *job = s_wasiJobsHead; s_wasiJobsHead = nullptr; @@ -368,6 +364,15 @@ extern "C" void QCALLTYPE EventPipeInternal_WasiRunJobs(QCallExceptionStatus* qc WasiAppendJob(job); job = next; } +} + +extern "C" void QCALLTYPE EventPipeInternal_WasiRunJobs(QCallExceptionStatus* qcallError) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + + ep_rt_coreclr_wasi_run_jobs(); END_QCALL; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index 50550b6a5af23e..074425c7d660a7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -56,11 +56,12 @@ internal static T PollWasiEventLoopUntilResolved(Task mainTask) s_mainTask = mainTask; while (!mainTask.IsCompleted) { - ThreadPoolWorkQueue.Dispatch(); - WasiFinalizerScheduler.DrainIfPending(); -#if FEATURE_PERFTRACING && CORECLR +#if FEATURE_PERFTRACING && CORECLR && !FEATURE_MULTITHREADING + // Before Dispatch, which can block in wasi:io/poll, so the pump's timer is registered first. WasiEventPipeJobs.EnsurePumpIfPending(); #endif + ThreadPoolWorkQueue.Dispatch(); + WasiFinalizerScheduler.DrainIfPending(); } } finally @@ -81,11 +82,12 @@ internal static void PollWasiEventLoopUntilResolvedVoid(Task mainTask) s_mainTask = mainTask; while (!mainTask.IsCompleted) { - ThreadPoolWorkQueue.Dispatch(); - WasiFinalizerScheduler.DrainIfPending(); -#if FEATURE_PERFTRACING && CORECLR +#if FEATURE_PERFTRACING && CORECLR && !FEATURE_MULTITHREADING + // Before Dispatch, which can block in wasi:io/poll, so the pump's timer is registered first. WasiEventPipeJobs.EnsurePumpIfPending(); #endif + ThreadPoolWorkQueue.Dispatch(); + WasiFinalizerScheduler.DrainIfPending(); } } finally diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c index 44cd721f0f775b..17d63b49f1a853 100644 --- a/src/native/eventpipe/ep-session.c +++ b/src/native/eventpipe/ep-session.c @@ -161,8 +161,8 @@ static size_t streaming_loop_tick(EventPipeSession *const session) { ok = ep_session_write_all_buffers_to_file (session, &events_written); EP_GCX_PREEMP_EXIT if (!ok) { + // Keep the job so the next tick sees streaming disabled and releases its reference. ep_disable ((EventPipeSessionID)session); - return 1; // done } return 0; // continue } @@ -191,8 +191,8 @@ session_create_streaming_thread (EventPipeSession *session) ep_session_inc_ref (session); ep_rt_volatile_store_uint32_t (&session->started, 1); if (!ep_rt_queue_job ((void *)streaming_loop_tick, (void *)session)) { - // The host can't run jobs, so drop the job's reference. Buffered events are - // flushed when the session is disabled. + // Release the job's reference directly; ep_session_dec_ref asserts streaming is + // disabled, and the session's own reference keeps it alive. ep_rt_atomic_dec_uint32_t (&session->ref_count); } #endif From 8d0513a97a66f01785d2c3a2b7f95db159448ea0 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 2 Oct 2026 21:55:05 -0500 Subject: [PATCH 4/5] [wasi] Regenerate CoreCLR WASI call helpers with EventPipe enabled The checked-in WASI call-helper tables were generated while FEATURE_PERFTRACING was off, so they lacked the reverse thunk for EventPipeEventProvider.Callback and the interpreter-to-native thunks for the EventPipe and NativeRuntimeEventSource QCalls. Any EventSource creation then hit "unknown thunk for unmanaged callers only method" in corerun builds that use these tables (the WASI runtime-test lane). Regenerated with src/coreclr/vm/wasm/generate-coreclr-helpers against the WASI testhost. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../wasi/callhelpers-interp-to-managed.cpp | 70 +++++++++++++++++++ .../vm/wasm/wasi/callhelpers-reverse.cpp | 14 ++++ 2 files changed, 84 insertions(+) diff --git a/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp b/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp index bab5632c834b02..1cab6a0762ff7d 100644 --- a/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp +++ b/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp @@ -316,6 +316,12 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I64(2)); } + static void CallFunc_I32_I32_I64_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + int32_t (*fptr)(int32_t, int32_t, int64_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int64_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I64(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7)); + } + static void CallFunc_I32_I32_I64_I64_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int64_t, int64_t, int32_t) = (int32_t (*)(int32_t, int32_t, int64_t, int64_t, int32_t))pcode; @@ -372,6 +378,18 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I64(0)); } + static void CallFunc_I64_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + int32_t (*fptr)(int64_t, int32_t) = (int32_t (*)(int64_t, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1)); + } + + static void CallFunc_I64_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + int32_t (*fptr)(int64_t, int32_t, int32_t) = (int32_t (*)(int64_t, int32_t, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2)); + } + static void CallFunc_I64_I32_I64_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int64_t, int32_t, int64_t, int32_t, int32_t) = (int32_t (*)(int64_t, int32_t, int64_t, int32_t, int32_t))pcode; @@ -397,12 +415,24 @@ namespace *((int64_t*)pRet) = (*fptr)(ARG_I32(0)); } + static void CallFunc_I32_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + int64_t (*fptr)(int32_t, int32_t) = (int64_t (*)(int32_t, int32_t))pcode; + *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1)); + } + static void CallFunc_I32_I32_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int32_t, int32_t) = (int64_t (*)(int32_t, int32_t, int32_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2)); } + static void CallFunc_I32_I32_I32_I32_I32_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + int64_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int64_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; + *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); + } + static void CallFunc_I32_I32_I32_I64_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int32_t, int32_t, int64_t) = (int64_t (*)(int32_t, int32_t, int32_t, int64_t))pcode; @@ -523,6 +553,24 @@ namespace (*fptr)(&framePointer, ARG_I32(0), pPortableEntryPoint); } + static void CallFunc_F64_F64_F64_F64_F64_F64_F64_F64_F64_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + void (*fptr)(double, double, double, double, double, double, double, double, double, int32_t, int32_t, int32_t) = (void (*)(double, double, double, double, double, double, double, double, double, int32_t, int32_t, int32_t))pcode; + (*fptr)(ARG_F64(0), ARG_F64(1), ARG_F64(2), ARG_F64(3), ARG_F64(4), ARG_F64(5), ARG_F64(6), ARG_F64(7), ARG_F64(8), ARG_I32(9), ARG_I32(10), ARG_I32(11)); + } + + static void CallFunc_F64_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + void (*fptr)(double, int32_t, int32_t) = (void (*)(double, int32_t, int32_t))pcode; + (*fptr)(ARG_F64(0), ARG_I32(1), ARG_I32(2)); + } + + static void CallFunc_F64_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + void (*fptr)(double, int32_t, int32_t, int32_t, int32_t) = (void (*)(double, int32_t, int32_t, int32_t, int32_t))pcode; + (*fptr)(ARG_F64(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); + } + NOINLINE static void CallFunc_F64_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -567,6 +615,12 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2), ARG_IND(3), ARG_I32(4), ARG_I32(5), ARG_I32(6)); } + static void CallFunc_I32_I32_F64_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + void (*fptr)(int32_t, int32_t, double, int32_t) = (void (*)(int32_t, int32_t, double, int32_t))pcode; + (*fptr)(ARG_I32(0), ARG_I32(1), ARG_F64(2), ARG_I32(3)); + } + static void CallFunc_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t))pcode; @@ -609,6 +663,12 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6)); } + static void CallFunc_I32_I32_I32_I32_I64_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) + { + void (*fptr)(int32_t, int32_t, int32_t, int32_t, int64_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int64_t, int32_t))pcode; + (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I64(4), ARG_I32(5)); + } + NOINLINE static void CallFunc_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -698,6 +758,7 @@ const StringToPortableSigThunk g_portableCallHelperThunks[] = { { "Miiiil", (void*)&CallFunc_I32_I32_I32_I64_RetI32 }, { "Miiiip", (void*)&CallFunc_I32_I32_I32_RetI32_PE }, { "Miiil", (void*)&CallFunc_I32_I32_I64_RetI32 }, + { "Miiiliiiii", (void*)&CallFunc_I32_I32_I64_I32_I32_I32_I32_I32_RetI32 }, { "Miiilli", (void*)&CallFunc_I32_I32_I64_I64_I32_RetI32 }, { "Miiip", (void*)&CallFunc_I32_I32_RetI32_PE }, { "Miil", (void*)&CallFunc_I32_I64_RetI32 }, @@ -707,11 +768,15 @@ const StringToPortableSigThunk g_portableCallHelperThunks[] = { { "Miilli", (void*)&CallFunc_I32_I64_I64_I32_RetI32 }, { "Miip", (void*)&CallFunc_I32_RetI32_PE }, { "Mil", (void*)&CallFunc_I64_RetI32 }, + { "Mili", (void*)&CallFunc_I64_I32_RetI32 }, + { "Milii", (void*)&CallFunc_I64_I32_I32_RetI32 }, { "Mililii", (void*)&CallFunc_I64_I32_I64_I32_I32_RetI32 }, { "Mip", (void*)&CallFunc_Void_RetI32_PE }, { "Ml", (void*)&CallFunc_Void_RetI64 }, { "Mli", (void*)&CallFunc_I32_RetI64 }, + { "Mlii", (void*)&CallFunc_I32_I32_RetI64 }, { "Mliii", (void*)&CallFunc_I32_I32_I32_RetI64 }, + { "Mliiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetI64 }, { "Mliiil", (void*)&CallFunc_I32_I32_I32_I64_RetI64 }, { "Mlili", (void*)&CallFunc_I32_I64_I32_RetI64 }, { "Mlillp", (void*)&CallFunc_I32_I64_I64_RetI64_PE }, @@ -731,6 +796,9 @@ const StringToPortableSigThunk g_portableCallHelperThunks[] = { { "MvS8iiiiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_I32_I32_RetVoid }, { "MvS8iiiiiiiiiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid }, { "MvTp", (void*)&CallFunc_This_RetVoid_PE }, + { "Mvdddddddddiii", (void*)&CallFunc_F64_F64_F64_F64_F64_F64_F64_F64_F64_I32_I32_I32_RetVoid }, + { "Mvdii", (void*)&CallFunc_F64_I32_I32_RetVoid }, + { "Mvdiiii", (void*)&CallFunc_F64_I32_I32_I32_I32_RetVoid }, { "Mvdiip", (void*)&CallFunc_F64_I32_I32_RetVoid_PE }, { "Mvfiip", (void*)&CallFunc_F32_I32_I32_RetVoid_PE }, { "Mvi", (void*)&CallFunc_I32_RetVoid }, @@ -738,6 +806,7 @@ const StringToPortableSigThunk g_portableCallHelperThunks[] = { { "Mvii", (void*)&CallFunc_I32_I32_RetVoid }, { "MviiS8S8ii", (void*)&CallFunc_I32_I32_S8_S8_I32_I32_RetVoid }, { "MviiS8S8iii", (void*)&CallFunc_I32_I32_S8_S8_I32_I32_I32_RetVoid }, + { "Mviidi", (void*)&CallFunc_I32_I32_F64_I32_RetVoid }, { "Mviii", (void*)&CallFunc_I32_I32_I32_RetVoid }, { "MviiiS8S8i", (void*)&CallFunc_I32_I32_I32_S8_S8_I32_RetVoid }, { "MviiiS8S8ii", (void*)&CallFunc_I32_I32_I32_S8_S8_I32_I32_RetVoid }, @@ -745,6 +814,7 @@ const StringToPortableSigThunk g_portableCallHelperThunks[] = { { "Mviiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_RetVoid }, { "Mviiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetVoid }, { "Mviiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_RetVoid }, + { "Mviiiili", (void*)&CallFunc_I32_I32_I32_I32_I64_I32_RetVoid }, { "Mviiip", (void*)&CallFunc_I32_I32_I32_RetVoid_PE }, { "Mviip", (void*)&CallFunc_I32_I32_RetVoid_PE }, { "Mvili", (void*)&CallFunc_I32_I64_I32_RetVoid }, diff --git a/src/coreclr/vm/wasm/wasi/callhelpers-reverse.cpp b/src/coreclr/vm/wasm/wasi/callhelpers-reverse.cpp index f60c87519e1a7a..9cd802b741c60d 100644 --- a/src/coreclr/vm/wasm/wasi/callhelpers-reverse.cpp +++ b/src/coreclr/vm/wasm/wasi/callhelpers-reverse.cpp @@ -92,6 +92,19 @@ static void Call_System_Private_CoreLib_System_Runtime_CompilerServices_RuntimeH ExecuteInterpretedMethodFromUnmanaged(MD_System_Private_CoreLib_System_Runtime_CompilerServices_RuntimeHelpers_CallToString_I32_I32_I32_RetVoid, (int8_t*)args, sizeof(args), nullptr, (PCODE)&Call_System_Private_CoreLib_System_Runtime_CompilerServices_RuntimeHelpers_CallToString_I32_I32_I32_RetVoid); } +static MethodDesc* MD_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid = nullptr; +static void Call_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid(void * arg0, int32_t arg1, uint32_t arg2, int64_t arg3, int64_t arg4, void * arg5, void * arg6) +{ + // Lazy lookup of MethodDesc for the function export scenario. + if (!MD_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid) + { + LookupUnmanagedCallersOnlyMethodByName("System.Diagnostics.Tracing.EventPipeEventProvider, System.Private.CoreLib", "Callback", &MD_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid); + } + + int64_t args[7] = { (int64_t)arg0, (int64_t)arg1, (int64_t)arg2, (int64_t)arg3, (int64_t)arg4, (int64_t)arg5, (int64_t)arg6 }; + ExecuteInterpretedMethodFromUnmanaged(MD_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid, (int8_t*)args, sizeof(args), nullptr, (PCODE)&Call_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid); +} + static MethodDesc* MD_System_Private_CoreLib_System_StubHelpers_MngdRefCustomMarshaler_ClearManaged_I32_I32_I32_I32_RetVoid = nullptr; static void Call_System_Private_CoreLib_System_StubHelpers_MngdRefCustomMarshaler_ClearManaged_I32_I32_I32_I32_RetVoid(void * arg0, void * arg1, void * arg2, void * arg3) { @@ -1023,6 +1036,7 @@ const ReverseThunkMapEntry g_ReverseThunks[] = { 3962535319, "CallEntryPoint#5:System.Private.CoreLib:System:Environment", { &MD_System_Private_CoreLib_System_Environment_CallEntryPoint_I32_I32_I32_I32_I32_RetVoid, (void*)&Call_System_Private_CoreLib_System_Environment_CallEntryPoint_I32_I32_I32_I32_I32_RetVoid } }, { 1821934012, "CallStartupHook#2:System.Private.CoreLib:System:StartupHookProvider", { &MD_System_Private_CoreLib_System_StartupHookProvider_CallStartupHook_I32_I32_RetVoid, (void*)&Call_System_Private_CoreLib_System_StartupHookProvider_CallStartupHook_I32_I32_RetVoid } }, { 2915047114, "CallToString#3:System.Private.CoreLib:System.Runtime.CompilerServices:RuntimeHelpers", { &MD_System_Private_CoreLib_System_Runtime_CompilerServices_RuntimeHelpers_CallToString_I32_I32_I32_RetVoid, (void*)&Call_System_Private_CoreLib_System_Runtime_CompilerServices_RuntimeHelpers_CallToString_I32_I32_I32_RetVoid } }, + { 4077371982, "Callback#7:System.Private.CoreLib:System.Diagnostics.Tracing:EventPipeEventProvider", { &MD_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid, (void*)&Call_System_Private_CoreLib_System_Diagnostics_Tracing_EventPipeEventProvider_Callback_I32_I32_I32_I64_I64_I32_I32_RetVoid } }, { 3358042195, "ClearManaged#4:System.Private.CoreLib:System.StubHelpers:MngdRefCustomMarshaler", { &MD_System_Private_CoreLib_System_StubHelpers_MngdRefCustomMarshaler_ClearManaged_I32_I32_I32_I32_RetVoid, (void*)&Call_System_Private_CoreLib_System_StubHelpers_MngdRefCustomMarshaler_ClearManaged_I32_I32_I32_I32_RetVoid } }, { 2311968855, "ClearNative#4:System.Private.CoreLib:System.StubHelpers:MngdRefCustomMarshaler", { &MD_System_Private_CoreLib_System_StubHelpers_MngdRefCustomMarshaler_ClearNative_I32_I32_I32_I32_RetVoid, (void*)&Call_System_Private_CoreLib_System_StubHelpers_MngdRefCustomMarshaler_ClearNative_I32_I32_I32_I32_RetVoid } }, { 3378852959, "ConfigCallback#5:System.Private.CoreLib:System:GC", { &MD_System_Private_CoreLib_System_GC_ConfigCallback_I32_I32_I32_I32_I64_RetVoid, (void*)&Call_System_Private_CoreLib_System_GC_ConfigCallback_I32_I32_I32_I32_I64_RetVoid } }, From 8b482c973fbdb018829b7ce803c99969b856f190 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 5 Oct 2026 17:51:34 +0200 Subject: [PATCH 5/5] Re-enable ActivityTracking tests on WASI EventPipe is now enabled for CoreCLR WASI, so the activity-id tests pass. Mono WASI does not run System.Diagnostics.Tracing.Tests (only its smoke and AOT lists), so removing the WASI ActiveIssue does not expose Mono. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../tests/BasicEventSourceTest/ActivityTracking.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs index cb7390b021c58b..d467ed3a7e5180 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs @@ -53,7 +53,6 @@ public void IsSupported() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/129088", typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid), nameof(PlatformDetection.IsMonoRuntime))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/134963", TestPlatforms.Wasi)] public void StartStopCreatesActivity() { using ActivityEventListener l = new ActivityEventListener(); @@ -70,7 +69,6 @@ public void StartStopCreatesActivity() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/129088", typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid), nameof(PlatformDetection.IsMonoRuntime))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/134963", TestPlatforms.Wasi)] public async Task ActivityFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); @@ -120,7 +118,6 @@ private async Task YieldTwoActivitiesDeep(ActivityEventSource es) // Compare with SetCurrentActivityIdAfterEventDoesNotFlowAsync below. [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/129088", typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid), nameof(PlatformDetection.IsMonoRuntime))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/134963", TestPlatforms.Wasi)] public async Task SetCurrentActivityIdBeforeEventFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); @@ -147,7 +144,6 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync() // Compare with SetCurrentActivityIdBeforeEventFlowsAsync above. [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/129088", typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid), nameof(PlatformDetection.IsMonoRuntime))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/134963", TestPlatforms.Wasi)] public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync() { using ActivityEventListener l = new ActivityEventListener();