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..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
@@ -1111,6 +1123,8 @@ 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
EP_UNREACHABLE ("Not implemented on this platform");
return false;
diff --git a/src/coreclr/vm/eventpipeinternal.cpp b/src/coreclr/vm/eventpipeinternal.cpp
index 5a2dc9933c800c..72eafc9f1e9cab 100644
--- a/src/coreclr/vm/eventpipeinternal.cpp
+++ b/src/coreclr/vm/eventpipeinternal.cpp
@@ -296,4 +296,86 @@ 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;
+}
+
+void ep_rt_coreclr_wasi_run_jobs()
+{
+ // 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;
+ }
+}
+
+extern "C" void QCALLTYPE EventPipeInternal_WasiRunJobs(QCallExceptionStatus* qcallError)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ ep_rt_coreclr_wasi_run_jobs();
+
+ 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/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 } },
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/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..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,6 +56,10 @@ internal static T PollWasiEventLoopUntilResolved(Task mainTask)
s_mainTask = mainTask;
while (!mainTask.IsCompleted)
{
+#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();
}
@@ -78,6 +82,10 @@ internal static void PollWasiEventLoopUntilResolvedVoid(Task mainTask)
s_mainTask = mainTask;
while (!mainTask.IsCompleted)
{
+#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();
}
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;
+ }
+ }
+ }
+}
diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c
index 09c6a12b41f104..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
}
@@ -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)) {
+ // 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
}