}
+#if SIZEOF_VOID_P == 4 && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+static gboolean is_wow64 = FALSE;
+#endif
+
+/* We do this at init time to avoid potential races with module opening */
+void
+mono_threads_platform_init (void)
+{
+#if SIZEOF_VOID_P == 4 && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+ LPFN_ISWOW64PROCESS is_wow64_func = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandle (TEXT ("kernel32")), "IsWow64Process");
+ if (is_wow64_func)
+ is_wow64_func (GetCurrentProcess (), &is_wow64);
+#endif
+}
+
+/*
+ * When running x86 process under x64 system syscalls are done through WoW64. This
+ * needs to do a transition from x86 mode to x64 so it can syscall into the x64 system.
+ * Apparently this transition invalidates the ESP that we would get from calling
+ * GetThreadContext, so we would fail to scan parts of the thread stack. We attempt
+ * to query whether the thread is in such a transition so we try to restart it later.
+ * We check CONTEXT_EXCEPTION_ACTIVE for this, which is highly undocumented.
+ */
+gboolean
+mono_threads_platform_in_critical_region (MonoNativeThreadId tid)
+{
+ gboolean ret = FALSE;
+#if SIZEOF_VOID_P == 4 && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+/* FIXME On cygwin these are not defined */
+#if defined(CONTEXT_EXCEPTION_REQUEST) && defined(CONTEXT_EXCEPTION_REPORTING) && defined(CONTEXT_EXCEPTION_ACTIVE)
+ if (is_wow64) {
+ HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, tid);
+ if (handle) {
+ CONTEXT context;
+ ZeroMemory (&context, sizeof (CONTEXT));
+ context.ContextFlags = CONTEXT_EXCEPTION_REQUEST;
+ if (GetThreadContext (handle, &context)) {
+ if ((context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) &&
+ (context.ContextFlags & CONTEXT_EXCEPTION_ACTIVE))
+ ret = TRUE;
+ }
+ CloseHandle (handle);
+ }
+ }
+#endif
+#endif
+ return ret;
+}
+
gboolean
mono_threads_platform_yield (void)
{
mono_thread_smr_init ();
mono_threads_suspend_init ();
mono_threads_coop_init ();
+ mono_threads_platform_init ();
#if defined(__MACH__)
mono_mach_init (thread_info_key);
gpointer stack_start;
MonoThreadUnwindState *state;
+ if (mono_threads_platform_in_critical_region (mono_thread_info_get_tid (info)))
+ return TRUE;
+
/* Are we inside a system critical region? */
if (info->inside_critical_region)
return TRUE;
int mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid);
void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize);
+void mono_threads_platform_init (void);
+gboolean mono_threads_platform_in_critical_region (MonoNativeThreadId tid);
gboolean mono_threads_platform_yield (void);
void mono_threads_platform_exit (gsize exit_code);