[sgen] Basic Win32 support.
authorMark Probst <mark.probst@gmail.com>
Tue, 4 Oct 2011 09:36:45 +0000 (11:36 +0200)
committerMark Probst <mark.probst@gmail.com>
Tue, 4 Oct 2011 20:36:31 +0000 (22:36 +0200)
13 files changed:
configure.in
mono/io-layer/mono-mutex.h
mono/metadata/Makefile.am
mono/metadata/sgen-archdep.h
mono/metadata/sgen-cardtable.c
mono/metadata/sgen-gc.c
mono/metadata/sgen-gc.h
mono/metadata/sgen-os-win32.c [new file with mode: 0644]
mono/metadata/threads.c
mono/utils/gc_wrapper.h
mono/utils/mono-mmap.c
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.h

index 9ea215174668015a914c4cf2372c58bea1594942..cd4223dff3a69532bdb1e9ac2fcb0729ada5396f 100644 (file)
@@ -2220,6 +2220,7 @@ case "$host" in
                        sgen_supported=true
                        ;;
                  cygwin*)
+                       sgen_supported=true
                        have_visibility_hidden=no                 
                        ;;
                  haiku*)
index 74ff0655d42bb4cdd2aa68ab7dc9e4e810a7e094..b01c4feca98c78bd25c431c44ee9a0f75e8d4f28 100644 (file)
@@ -167,6 +167,7 @@ typedef HANDLE mono_cond_t;
 
 #define mono_mutex_init(mutex,attr) InitializeCriticalSection((mutex))
 #define mono_mutex_lock(mutex) EnterCriticalSection((mutex))
+#define mono_mutex_trylock(mutex) TryEnterCriticalSection((mutex))
 #define mono_mutex_unlock(mutex)  LeaveCriticalSection((mutex))
 #define mono_mutex_destroy(mutex) DeleteCriticalSection((mutex))
 
@@ -178,7 +179,6 @@ typedef HANDLE mono_cond_t;
 #define mono_cond_broadcast(cond) (!SetEvent(*(cond)))
 #define mono_cond_destroy(cond) CloseHandle(*(cond))
 
-#define MONO_MUTEX_INITIALIZER NULL
 #define MONO_COND_INITIALIZER NULL
 #endif
 
index 248dc77a29ca58d744a04ef2f4732f3eb9d7162a..fa1376371f87058708a5cec133fa6569950a16f5 100644 (file)
@@ -189,6 +189,7 @@ libmonoruntime_la_SOURCES = \
        security-manager.h      \
        sgen-os-posix.c         \
        sgen-os-mach.c          \
+       sgen-os-win32.c         \
        sgen-gc.c               \
        sgen-internal.c         \
        sgen-pinned-allocator.c \
index dda1665245eea42835129a387451f0be0dfe60bf..d153b3d89d8ccd288c3bcfe738f0547e736974b4 100644 (file)
 #define REDZONE_SIZE   0
 
 #define ARCH_NUM_REGS 8
+
+#ifdef MONO_ARCH_HAS_MONO_CONTEXT
 #define USE_MONO_CTX
+#else
+#define ARCH_STORE_REGS(ptr)   \
+       __asm__ __volatile__(   \
+               "mov %%edi,0(%0)\n"     \
+               "mov %%esi,4(%0)\n"     \
+               "mov %%ebx,8(%0)\n"     \
+               "mov %%edx,12(%0)\n"    \
+               "mov %%ecx,16(%0)\n"    \
+               "mov %%eax,20(%0)\n"    \
+               "mov %%ebp,24(%0)\n"    \
+               "mov %%esp,28(%0)\n"    \
+               :                       \
+               : "r" (ptr)     \
+       )
+#endif
 
 /*FIXME, move this to mono-sigcontext as this is generaly useful.*/
 #define ARCH_SIGCTX_SP(ctx)    (UCONTEXT_REG_ESP ((ctx)))
index 158c269d53ca7edb8072cb753fbfe9225904f5bc..e56f0480162b2ca24ca781f4ea56d0eba06c4a5c 100644 (file)
@@ -34,7 +34,9 @@
 //#define CARDTABLE_STATS
 
 #include <unistd.h>
+#ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
+#endif
 #include <sys/types.h>
 
 guint8 *sgen_cardtable;
index 774f688b7ec3b696ac3561addf6c1970af7e3c35..38c35409886dd068a35e4c984af4f70e08c99259 100644 (file)
@@ -4582,6 +4582,7 @@ mono_sgen_fill_thread_info_for_suspend (SgenThreadInfo *info)
  */
 //#define XDOMAIN_CHECKS_IN_WBARRIER
 
+#ifndef HOST_WIN32
 #ifndef SGEN_BINARY_PROTOCOL
 #ifndef HEAVY_STATISTICS
 #define MANAGED_ALLOCATION
@@ -4590,6 +4591,7 @@ mono_sgen_fill_thread_info_for_suspend (SgenThreadInfo *info)
 #endif
 #endif
 #endif
+#endif
 
 static gboolean
 is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip);
@@ -4636,7 +4638,11 @@ restart_threads_until_none_in_managed_allocator (void)
                mono_sgen_wait_for_suspend_ack (restart_count);
 
                if (sleep_duration < 0) {
+#ifdef HOST_WIN32
+                       SwitchToThread ();
+#else
                        sched_yield ();
+#endif
                        sleep_duration = 0;
                } else {
                        g_usleep (sleep_duration);
@@ -6603,7 +6609,9 @@ mono_gc_base_init (void)
        cb.thread_unregister = sgen_thread_unregister;
        cb.thread_attach = sgen_thread_attach;
        cb.mono_method_is_critical = (gpointer)is_critical_method;
+#ifndef HOST_WIN32
        cb.mono_gc_pthread_create = (gpointer)mono_gc_pthread_create;
+#endif
 
        mono_threads_init (&cb, sizeof (SgenThreadInfo));
 
index 542dd1a5e58258868bf059ce024be0840ed79e3c..a83eb2b4f605ecbfd7a294df6f3dbbfe0ebbc40a 100644 (file)
@@ -126,19 +126,20 @@ struct _SgenThreadInfo {
        gpointer stopped_ip;    /* only valid if the thread is stopped */
        MonoDomain *stopped_domain; /* ditto */
 
-#if defined(__MACH__)
 #ifdef USE_MONO_CTX
+#ifdef __MACH__
        MonoContext ctx;                /* ditto */
-#else
-       gpointer regs[ARCH_NUM_REGS];       /* ditto */
 #endif
-#endif
-
-#ifdef USE_MONO_CTX
        MonoContext *monoctx;   /* ditto */
+
 #else
+
+#if defined(__MACH__) || defined(HOST_WIN32)
+       gpointer regs[ARCH_NUM_REGS];       /* ditto */
+#endif
        gpointer *stopped_regs;     /* ditto */
 #endif
+
 #ifndef HAVE_KW_THREAD
        char *tlab_start;
        char *tlab_next;
@@ -250,8 +251,10 @@ typedef struct _SgenPinnedChunk SgenPinnedChunk;
                } while (InterlockedCompareExchange (&(x), __old_x + (i), __old_x) != __old_x); \
        } while (0)
 
+#ifndef HOST_WIN32
 /* we intercept pthread_create calls to know which threads exist */
 #define USE_PTHREAD_INTERCEPT 1
+#endif
 
 #ifdef HEAVY_STATISTICS
 #define HEAVY_STAT(x)  x
diff --git a/mono/metadata/sgen-os-win32.c b/mono/metadata/sgen-os-win32.c
new file mode 100644 (file)
index 0000000..7d38808
--- /dev/null
@@ -0,0 +1,125 @@
+#include "config.h"
+
+#if defined(HAVE_SGEN_GC) && defined(HOST_WIN32)
+
+#include <windows.h>
+
+#include "metadata/sgen-gc.h"
+#include "metadata/gc-internal.h"
+
+gboolean
+mono_sgen_resume_thread (SgenThreadInfo *info)
+{
+       DWORD id = mono_thread_info_get_tid (info);
+       HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
+       DWORD result;
+
+       g_assert (handle);
+
+       result = ResumeThread (handle);
+       g_assert (result != (DWORD)-1);
+
+       CloseHandle (handle);
+
+       return result != (DWORD)-1;
+}
+
+gboolean
+mono_sgen_suspend_thread (SgenThreadInfo *info)
+{
+       DWORD id = mono_thread_info_get_tid (info);
+       HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
+       CONTEXT context;
+       DWORD result;
+
+       g_assert (handle);
+
+       result = SuspendThread (handle);
+       g_assert (result != (DWORD)-1);
+       if (result == (DWORD)-1) {
+               CloseHandle (handle);
+               return FALSE;
+       }
+
+       context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
+
+       if (!GetThreadContext (handle, &context)) {
+               g_assert_not_reached ();
+               ResumeThread (handle);
+               CloseHandle (handle);
+               return FALSE;
+       }
+
+       g_assert (context.ContextFlags & CONTEXT_INTEGER);
+       g_assert (context.ContextFlags & CONTEXT_CONTROL);
+
+       CloseHandle (handle);
+
+       info->stopped_domain = NULL; /* FIXME: implement! */
+       info->stopped_ip = (gpointer)context.Eip;
+       info->stack_start = (char*)context.Esp - REDZONE_SIZE;
+
+       info->regs [0] = context.Edi;
+       info->regs [1] = context.Esi;
+       info->regs [2] = context.Ebx;
+       info->regs [3] = context.Edx;
+       info->regs [4] = context.Ecx;
+       info->regs [5] = context.Eax;
+       info->regs [6] = context.Ebp;
+       info->regs [7] = context.Esp;
+       info->stopped_regs = &info->regs;
+
+       /* Notify the JIT */
+       if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
+               mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL);
+
+       return TRUE;
+}
+
+void
+mono_sgen_wait_for_suspend_ack (int count)
+{
+       /* Win32 suspend/resume is synchronous, so we don't need to wait for anything */
+}
+
+int
+mono_sgen_thread_handshake (BOOL suspend)
+{
+       SgenThreadInfo *info;
+       SgenThreadInfo *current = mono_thread_info_current ();
+       int count = 0;
+
+       FOREACH_THREAD_SAFE (info) {
+               if (info == current)
+                       continue;
+               if (suspend) {
+                       g_assert (!info->doing_handshake);
+                       info->doing_handshake = TRUE;
+
+                       if (!mono_sgen_suspend_thread (info))
+                               continue;
+               } else {
+                       g_assert (info->doing_handshake);
+                       info->doing_handshake = FALSE;
+
+                       if (!mono_sgen_resume_thread (info))
+                               continue;
+               }
+
+               ++count;
+       } END_FOREACH_THREAD_SAFE
+       return count;
+}
+
+void
+mono_sgen_os_init (void)
+{
+}
+
+int
+mono_gc_get_suspend_signal (void)
+{
+       return -1;
+}
+
+#endif
index 422dff84d531a2ea06ab741bdcfda7e2b8196a24..ee1db31e9b79363b9470f0941bc65e835b7cdbe5 100644 (file)
@@ -651,7 +651,7 @@ gpointer mono_create_thread (WapiSecurityAttributes *security,
 #ifdef HOST_WIN32
        DWORD real_tid;
 
-       res = CreateThread (security, stacksize, start, param, create, &real_tid);
+       res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
        if (tid)
                *tid = real_tid;
 #else
index d5af0da3cf4ec030c779f05e62641fdafba979ea..b4ea3770ad2af85b15e3a08af7de2fc77da7a5da 100644 (file)
 
 #elif defined(HAVE_SGEN_GC)
 
-#if defined(HOST_WIN32)
-#define CreateThread mono_gc_CreateThread
-
-#endif
-
 #else /* not Boehm and not sgen GC */
 #endif
 
index 17af2ab59e8b853ad7cc712b6c029d125dc15567..2d0e55302c05bf6b46f4edef5e14b5042a8f80a0 100644 (file)
@@ -62,6 +62,14 @@ malloc_shared_area (int pid)
        return sarea;
 }
 
+static char*
+aligned_address (char *mem, size_t size, size_t alignment)
+{
+       char *aligned = (char*)((gulong)(mem + (alignment - 1)) & ~(alignment - 1));
+       g_assert (aligned >= mem && aligned + size <= mem + size + alignment && !((gulong)aligned & (alignment - 1)));
+       return aligned;
+}
+
 #ifdef HOST_WIN32
 
 int
@@ -107,6 +115,25 @@ mono_valloc (void *addr, size_t length, int flags)
        return ptr;
 }
 
+void*
+mono_valloc_aligned (size_t length, size_t alignment, int flags)
+{
+       int prot = prot_from_flags (flags);
+       char *mem = VirtualAlloc (NULL, length + alignment, MEM_RESERVE, prot);
+       char *aligned;
+
+       g_assert (mem);
+
+       aligned = aligned_address (mem, length, alignment);
+
+       aligned = VirtualAlloc (aligned, length, MEM_COMMIT, prot);
+       g_assert (aligned);
+
+       return aligned;
+}
+
+#define HAVE_VALLOC_ALIGNED
+
 int
 mono_vfree (void *addr, size_t length)
 {
@@ -631,8 +658,7 @@ mono_valloc_aligned (size_t size, size_t alignment, int flags)
 
        g_assert (mem);
 
-       aligned = (char*)((gulong)(mem + (alignment - 1)) & ~(alignment - 1));
-       g_assert (aligned >= mem && aligned + size <= mem + size + alignment && !((gulong)aligned & (alignment - 1)));
+       aligned = aligned_address (mem, size, alignment);
 
        if (aligned > mem)
                mono_vfree (mem, aligned - mem);
index 3e153a74a2ff0fb71e1adc95512b67d7d8c23503..6a5a475f72d192b582dac53a025ce5f924bbde6c 100644 (file)
@@ -53,4 +53,63 @@ mono_threads_platform_free (MonoThreadInfo *info)
 {
 }
 
+typedef struct {
+       LPTHREAD_START_ROUTINE start_routine;
+       void *arg;
+       MonoSemType registered;
+       gboolean suspend;
+} ThreadStartInfo;
+
+static DWORD WINAPI
+inner_start_thread (LPVOID arg)
+{
+       ThreadStartInfo *start_info = arg;
+       void *t_arg = start_info->arg;
+       int post_result;
+       LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
+       DWORD result;
+
+       mono_thread_info_attach (&result);
+
+       post_result = MONO_SEM_POST (&(start_info->registered));
+       g_assert (!post_result);
+
+       if (start_info->suspend)
+               SuspendThread (GetCurrentThread ());
+
+       result = start_func (t_arg);
+
+       g_assert (!mono_domain_get ());
+
+       return result;
+}
+
+HANDLE
+mono_threads_CreateThread (LPSECURITY_ATTRIBUTES attributes, SIZE_T stack_size, LPTHREAD_START_ROUTINE start_routine,
+               LPVOID arg, DWORD creation_flags, LPDWORD thread_id)
+{
+       ThreadStartInfo *start_info;
+       HANDLE result;
+
+       start_info = g_malloc0 (sizeof (ThreadStartInfo));
+       if (!start_info)
+               return NULL;
+       MONO_SEM_INIT (&(start_info->registered), 0);
+       start_info->arg = arg;
+       start_info->start_routine = start_routine;
+       start_info->suspend = creation_flags & CREATE_SUSPENDED;
+       creation_flags &= ~CREATE_SUSPENDED;
+
+       result = CreateThread (attributes, stack_size, inner_start_thread, start_info, creation_flags, thread_id);
+
+       if (result) {
+               while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
+                       /*if (EINTR != errno) ABORT("sem_wait failed"); */
+               }
+       }
+       MONO_SEM_DESTROY (&(start_info->registered));
+       g_free (start_info);
+       return result;
+}
+
 #endif
index c220e34c35511a1bcb97cb3cf85935cd5af7feac..dd9f1b5811ee204696466ca92ea7eec09c830afd 100644 (file)
 #include <windows.h>
 
 typedef DWORD MonoNativeThreadId;
-typedef HANDLE MonoNativeThreadHandle;
+typedef HANDLE MonoNativeThreadHandle; /* unused */
+
+typedef DWORD mono_native_thread_return_t;
 
 #define mono_native_thread_id_get GetCurrentThreadId
 #define mono_native_thread_id_equals(a,b) ((a) == ((b))
 
+HANDLE mono_threads_CreateThread (LPSECURITY_ATTRIBUTES attributes, SIZE_T stack_size, LPTHREAD_START_ROUTINE start_routine,
+               LPVOID arg, DWORD creation_flags, LPDWORD thread_id) MONO_INTERNAL;
+
+#define mono_native_thread_create(id,func,arg) (CreateThread (NULL, 0, (func), (arg), 0, (id)) != NULL)
+
 #else
 
 #include <pthread.h>