diff --git a/mono/metadata/domain-internals.h b/mono/metadata/domain-internals.h index fbfe9d33680a..b9306058bc8f 100644 --- a/mono/metadata/domain-internals.h +++ b/mono/metadata/domain-internals.h @@ -315,6 +315,7 @@ struct _MonoDomain { MonoCoopMutex lock; MonoMemPool *mp; MonoCodeManager *code_mp; + void *gc_mp; /* * keep all the managed objects close to each other for the precise GC * For the Boehm GC we additionally keep close also other GC-tracked pointers. diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c index 227b555833e2..81a097ec4365 100644 --- a/mono/metadata/gc.c +++ b/mono/metadata/gc.c @@ -453,7 +453,7 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout) /* We don't support domain finalization without a GC */ if (mono_gc_is_null ()) - return FALSE; + return TRUE; mono_gc_collect (mono_gc_max_generation ()); diff --git a/mono/metadata/null-gc-handles.c b/mono/metadata/null-gc-handles.c index 60e372bd6e98..c19731f57433 100644 --- a/mono/metadata/null-gc-handles.c +++ b/mono/metadata/null-gc-handles.c @@ -23,6 +23,10 @@ static mono_mutex_t handle_section; #define lock_handles(handles) mono_os_mutex_lock (&handle_section) #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section) + +void mono_gc_handle_lock () { lock_handles (NULL); } +void mono_gc_handle_unlock () { unlock_handles (NULL); } + typedef struct { guint32 *bitmap; gpointer *entries; @@ -116,7 +120,7 @@ handle_data_alloc_entries (HandleData *handles) handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size); handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size); } else { - handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "GC Handle Table (Null)"); + handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Table (Null)"); } handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT); } @@ -183,7 +187,7 @@ handle_data_grow (HandleData *handles, gboolean track) handles->domain_ids = domain_ids; } else { gpointer *entries; - entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "GC Handle Table (Null)"); + entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Table (Null)"); mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size); mono_gc_free_fixed (handles->entries); handles->entries = entries; @@ -224,7 +228,7 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track) #endif unlock_handles (handles); res = MONO_GC_HANDLE (slot, handles->type); - mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj); + MONO_PROFILER_RAISE (gc_handle_created, (res, handles->type, obj)); return res; } @@ -416,7 +420,7 @@ mono_gchandle_free (guint32 gchandle) #endif /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/ unlock_handles (handles); - mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL); + MONO_PROFILER_RAISE (gc_handle_deleted, (gchandle, handles->type)); } /** @@ -431,7 +435,7 @@ mono_gchandle_free_domain (MonoDomain *domain) { guint type; - for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) { + for (type = HANDLE_TYPE_MIN; type <= HANDLE_PINNED; ++type) { guint slot; HandleData *handles = &gc_handles [type]; lock_handles (handles); @@ -455,6 +459,31 @@ mono_gchandle_free_domain (MonoDomain *domain) } } + +void +mono_gc_strong_handle_foreach (GFunc func, gpointer user_data) +{ + int gcHandleTypeIndex; + uint32_t i; + + lock_handles (handles); + + for (gcHandleTypeIndex = HANDLE_NORMAL; gcHandleTypeIndex <= HANDLE_PINNED; gcHandleTypeIndex++) + { + HandleData* handles = &gc_handles[gcHandleTypeIndex]; + + for (i = 0; i < handles->size; i++) + { + if (!slot_occupied (handles, i)) + continue; + if (handles->entries[i] != NULL) + func (handles->entries[i], user_data); + } + } + + unlock_handles (handles); +} + #else MONO_EMPTY_SOURCE_FILE (null_gc_handles); diff --git a/mono/metadata/null-gc.c b/mono/metadata/null-gc.c index 7f91ee38c0ad..9c69322b4df4 100644 --- a/mono/metadata/null-gc.c +++ b/mono/metadata/null-gc.c @@ -9,26 +9,116 @@ */ #include "config.h" + +typedef struct _NullGCThreadInfo NullGCThreadInfo; +#undef THREAD_INFO_TYPE +#define THREAD_INFO_TYPE NullGCThreadInfo + #include <glib.h> #include <mono/metadata/mono-gc.h> #include <mono/metadata/gc-internals.h> #include <mono/metadata/runtime.h> #include <mono/metadata/w32handle.h> #include <mono/utils/atomic.h> +#include <mono/utils/mono-mmap.h> #include <mono/utils/mono-threads.h> #include <mono/utils/mono-counters.h> #include <mono/metadata/null-gc-handles.h> + + +struct _NullGCThreadInfo { + MonoThreadInfo info; + + /* + * `skip` is set to TRUE when STW fails to suspend a thread, most probably because + * the underlying thread is dead. + */ + gboolean skip, suspend_done; + volatile int in_critical_region; + + /* + This is set the argument of mono_gc_set_skip_thread. + + A thread that knowingly holds no managed state can call this + function around blocking loops to reduce the GC burden by not + been scanned. + */ + gboolean gc_disabled; +// +//#ifdef SGEN_POSIX_STW +// /* This is -1 until the first suspend. */ +// int signal; +// /* FIXME: kill this, we only use signals on systems that have rt-posix, which doesn't have issues with duplicates. */ +// unsigned int stop_count; /* to catch duplicate signals. */ +//#endif +// +// gpointer runtime_data; +// +// void* stack_end; +// void* stack_start; +// void* stack_start_limit; +// +// MonoContext ctx; /* ditto */ +}; + #ifdef HAVE_NULL_GC static gboolean gc_inited = FALSE; +struct _GCMemChunk; +typedef struct _GCMemChunk GCMemChunk; + +struct _GCMemChunk +{ + GCMemChunk* next; + char* start_of_memory; + char* current_memory; + size_t length; +}; + +typedef struct GCMemPool +{ + GCMemChunk* chunks; + size_t page_size; +} GCMemPool; + +static mono_mutex_t nullgc_mutex; + +static GCMemPool* init_gc_mempool () +{ + GCMemPool* mp = g_new0 (GCMemPool, 1); + mp->page_size = mono_pagesize (); + + return mp; +} + +static void gc_free_mempool (GCMemPool* mp) +{ + if (!mp) + return; + + GCMemChunk* chunk = mp->chunks; + while (chunk) { + + int res = VirtualFree (chunk->start_of_memory, chunk->length, MEM_DECOMMIT); + g_assert (res); + + GCMemChunk* prev = chunk; + chunk = chunk->next; + g_free (prev); + } + g_free (mp); +} + void mono_gc_base_init (void) { if (gc_inited) return; + mono_os_mutex_init (&nullgc_mutex); + mono_counters_init (); #ifndef HOST_WIN32 @@ -36,7 +126,7 @@ mono_gc_base_init (void) #endif mono_thread_callbacks_init (); - mono_thread_info_init (sizeof (MonoThreadInfo)); + mono_thread_info_init (sizeof (NullGCThreadInfo)); mono_thread_info_attach (); @@ -190,22 +280,113 @@ mono_gc_make_root_descr_all_refs (int numbits) return NULL; } +#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) + void* mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { - return g_malloc0 (size); + //return g_malloc0 (size); + size += sizeof(size_t); + size = ALIGN_TO (size, mono_pagesize ()); + char* ret = VirtualAlloc (0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + *(size_t*)ret = size; + ret += sizeof (size_t); + return ret; } void mono_gc_free_fixed (void* addr) { - g_free (addr); + char* start = (char*)addr - sizeof (size_t); + size_t length = *(size_t*)start; + int res = VirtualFree (start, length, MEM_DECOMMIT); + g_assert (res); +} + +/* only one can be enabled at a time */ +#define GUARD_PRELUDE 0 +#define GUARD_POSTLUDE 0 + +static void* +gc_mempool_alloc (MonoDomain* domain, size_t size) +{ + void* ret = NULL; + mono_os_mutex_lock (&nullgc_mutex); + GCMemPool* mp = domain->gc_mp; + if (!mp) + mp = domain->gc_mp = init_gc_mempool (); + + // keep 16 byte alignment + size = ALIGN_TO (size, 16); + +#if GUARD_PRELUDE + GCMemChunk* chunk = g_new0 (GCMemChunk, 1);; + size_t chunk_size = MAX ((mp->page_size), ALIGN_TO (size, mp->page_size)); + chunk_size += mp->page_size; + + chunk->start_of_memory = chunk->current_memory = (char*)VirtualAlloc (0, chunk_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + chunk->current_memory += mp->page_size; + + DWORD old; + BOOL res = VirtualProtect (chunk->start_of_memory, mp->page_size, PAGE_NOACCESS, &old); + g_assert (res); + + ret = chunk->current_memory; + + + chunk->length = chunk_size; + + chunk->next = mp->chunks; + mp->chunks = chunk; +#elif GUARD_POSTLUDE + GCMemChunk* chunk = g_new0 (GCMemChunk, 1); + size_t chunk_size = MAX ((mp->page_size), ALIGN_TO (size, mp->page_size)); + chunk_size += mp->page_size; + + chunk->start_of_memory = chunk->current_memory = (char*)VirtualAlloc (0, chunk_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + /* offset to abut last page */ + chunk->current_memory += (chunk_size - mp->page_size - size); + + DWORD old; + BOOL res = VirtualProtect (chunk->start_of_memory + chunk_size - mp->page_size, mp->page_size, PAGE_NOACCESS, &old); + g_assert (res); + + ret = chunk->current_memory; + + + chunk->length = chunk_size; + + chunk->next = mp->chunks; + mp->chunks = chunk; +#else + + GCMemChunk* chunk = mp->chunks; + if (!chunk || ((chunk->current_memory + size) > (chunk->start_of_memory + chunk->length))) + { + chunk = g_new0 (GCMemChunk, 1); + size_t chunk_size = MAX ((4 * mp->page_size), ALIGN_TO (size, mp->page_size)); + chunk->start_of_memory = chunk->current_memory = (char*)VirtualAlloc (0, chunk_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + chunk->length = chunk_size; + + chunk->next = mp->chunks; + mp->chunks = chunk; + } + + ret = chunk->current_memory; + chunk->current_memory += size; + + g_assert (chunk->current_memory <= (chunk->start_of_memory + chunk->length)); +#endif + + mono_os_mutex_unlock (&nullgc_mutex); + + return ret; } void * mono_gc_alloc_obj (MonoVTable *vtable, size_t size) { - MonoObject *obj = g_calloc (1, size); + MonoObject *obj = gc_mempool_alloc (vtable->domain, size); obj->vtable = vtable; @@ -215,7 +396,7 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size) void * mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) { - MonoArray *obj = g_calloc (1, size); + MonoArray *obj = gc_mempool_alloc (vtable->domain, size); obj->obj.vtable = vtable; obj->max_length = max_length; @@ -226,7 +407,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) void * mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size) { - MonoArray *obj = g_calloc (1, size); + MonoArray *obj = gc_mempool_alloc (vtable->domain, size); obj->obj.vtable = vtable; obj->max_length = max_length; @@ -240,7 +421,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint void * mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len) { - MonoString *obj = g_calloc (1, size); + MonoString *obj = gc_mempool_alloc (vtable->domain, size); obj->object.vtable = vtable; obj->length = len; @@ -317,25 +498,25 @@ mono_gc_is_critical_method (MonoMethod *method) } gpointer -mono_gc_thread_attach (MonoThreadInfo* info) +mono_gc_thread_attach (NullGCThreadInfo* info) { - info->handle_stack = mono_handle_stack_alloc (); + info->info.handle_stack = mono_handle_stack_alloc (); return info; } void -mono_gc_thread_detach (MonoThreadInfo *p) +mono_gc_thread_detach (NullGCThreadInfo*p) { } void -mono_gc_thread_detach_with_lock (MonoThreadInfo *p) +mono_gc_thread_detach_with_lock (NullGCThreadInfo*p) { - mono_handle_stack_free (p->handle_stack); + mono_handle_stack_free (p->info.handle_stack); } gboolean -mono_gc_thread_in_critical_region (MonoThreadInfo *info) +mono_gc_thread_in_critical_region (NullGCThreadInfo*info) { return FALSE; } @@ -379,6 +560,7 @@ mono_gc_get_gc_name (void) void mono_gc_clear_domain (MonoDomain *domain) { + gc_free_mempool (domain->gc_mp); } void @@ -595,6 +777,226 @@ mono_gc_pending_finalizers (void) return FALSE; } +void +mono_gc_register_obj_with_weak_fields (void* obj) +{ + g_error ("Weak fields not supported by null gc"); +} + +static gboolean +nullgc_is_thread_in_current_stw (NullGCThreadInfo* info, int* reason) +{ + /* + A thread explicitly asked to be skiped because it holds no managed state. + This is used by TP and finalizer threads. + FIXME Use an atomic variable for this to avoid everyone taking the GC LOCK. + */ + if (info->gc_disabled) { + if (reason) + *reason = 1; + return FALSE; + } + + /* + We have detected that this thread is failing/dying, ignore it. + FIXME: can't we merge this with thread_is_dying? + */ + if (info->skip) { + if (reason) + *reason = 2; + return FALSE; + } + + /* + Suspending the current thread will deadlock us, bad idea. + */ + if (info == mono_thread_info_current ()) { + if (reason) + *reason = 3; + return FALSE; + } + + /* + We can't suspend the workers that will do all the heavy lifting. + FIXME Use some state bit in SgenThreadInfo for this. + */ + //if (sgen_thread_pool_is_thread_pool_thread (mono_thread_info_get_tid (info))) { + // if (reason) + // *reason = 4; + // return FALSE; + //} + + /* + The thread has signaled that it started to detach, ignore it. + FIXME: can't we merge this with skip + */ + if (!mono_thread_info_is_live (info)) { + if (reason) + *reason = 5; + return FALSE; + } + + return TRUE; +} + + +#define THREADS_STW_DEBUG(...) + +void +nullgc_unified_suspend_stop_world (void) +{ + int sleep_duration = -1; + + mono_threads_begin_global_suspend (); + // THREADS_STW_DEBUG ("[GC-STW-BEGIN][%p] *** BEGIN SUSPEND *** \n", mono_thread_info_get_tid (mono_thread_info_current ())); + + FOREACH_THREAD (info) { + info->skip = FALSE; + info->suspend_done = FALSE; + + int reason; + if (!nullgc_is_thread_in_current_stw (info, &reason)) { + THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] IGNORE thread %p skip %s reason %d\n", mono_thread_info_get_tid (info), info->skip ? "true" : "false", reason); + continue; + } + + info->skip = !mono_thread_info_begin_suspend (info); + + THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false"); + } FOREACH_THREAD_END + + mono_thread_info_current ()->suspend_done = TRUE; + mono_threads_wait_pending_operations (); + + for (;;) { + gint restart_counter = 0; + + FOREACH_THREAD (info) { + gint suspend_count; + + int reason = 0; + if (info->suspend_done || !nullgc_is_thread_in_current_stw (info, &reason)) { + THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE RESUME thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason); + continue; + } + + /* + All threads that reach here are pristine suspended. This means the following: + + - We haven't accepted the previous suspend as good. + - We haven't gave up on it for this STW (it's either bad or asked not to) + */ + if (!mono_thread_info_in_critical_location (info)) { + info->suspend_done = TRUE; + + THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info)); + continue; + } + + suspend_count = mono_thread_info_suspend_count (info); + if (!(suspend_count == 1)) + g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count); + + info->skip = !mono_thread_info_begin_resume (info); + if (!info->skip) + restart_counter += 1; + + THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false"); + } FOREACH_THREAD_END + + mono_threads_wait_pending_operations (); + + if (restart_counter == 0) + break; + + if (sleep_duration < 0) { + mono_thread_info_yield (); + sleep_duration = 0; + } + else { + g_usleep (sleep_duration); + sleep_duration += 10; + } + + FOREACH_THREAD (info) { + int reason = 0; + if (info->suspend_done || !nullgc_is_thread_in_current_stw (info, &reason)) { + THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason); + continue; + } + + if (!mono_thread_info_is_running (info)) { + THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not running\n", mono_thread_info_get_tid (info)); + continue; + } + + /*info->client_info.skip = !*/mono_thread_info_begin_suspend (info); + + // THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false"); + } FOREACH_THREAD_END + + mono_threads_wait_pending_operations (); + } + + FOREACH_THREAD (info) { + gpointer stopped_ip; + + int reason = 0; + if (!nullgc_is_thread_in_current_stw (info, &reason)) { + //g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ()); + + THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason); + continue; + } + + g_assert (info->suspend_done); + + //info->ctx = mono_thread_info_get_suspend_state (info)->ctx; + + /* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */ + //info->client_info.stack_start = (gpointer)((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE); + + //if (info->client_info.stack_start < info->client_info.info.stack_start_limit + // || info->client_info.stack_start >= info->client_info.info.stack_end) { + // /* + // * Thread context is in unhandled state, most likely because it is + // * dying. We don't scan it. + // * FIXME We should probably rework and check the valid flag instead. + // */ + // info->client_info.stack_start = NULL; + //} + + //stopped_ip = (gpointer)(MONO_CONTEXT_GET_IP (&info->client_info.ctx)); + + //binary_protocol_thread_suspend ((gpointer)mono_thread_info_get_tid (info), stopped_ip); + + //THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended, stopped_ip = %p, stack = %p -> %p\n", + // mono_thread_info_get_tid (info), stopped_ip, info->stack_start, info->stack_start ? info->info.stack_end : NULL); + } FOREACH_THREAD_END +} + +void +nullgc_unified_suspend_restart_world (void) +{ + THREADS_STW_DEBUG ("[GC-STW-END] *** BEGIN RESUME ***\n"); + FOREACH_THREAD (info) { + int reason = 0; + if (nullgc_is_thread_in_current_stw (info, &reason)) { + g_assert (mono_thread_info_begin_resume (info)); + THREADS_STW_DEBUG ("[GC-STW-RESUME-WORLD] RESUME thread %p\n", mono_thread_info_get_tid (info)); + + //binary_protocol_thread_restart ((gpointer)mono_thread_info_get_tid (info)); + } + else { + THREADS_STW_DEBUG ("[GC-STW-RESUME-WORLD] IGNORE thread %p, reason %d\n", mono_thread_info_get_tid (info), reason); + } + } FOREACH_THREAD_END + + mono_threads_wait_pending_operations (); + mono_threads_end_global_suspend (); +} + + #else MONO_EMPTY_SOURCE_FILE (null_gc); diff --git a/mono/metadata/unity-liveness.c b/mono/metadata/unity-liveness.c index 7f6c3df8f670..b97aa33446c3 100644 --- a/mono/metadata/unity-liveness.c +++ b/mono/metadata/unity-liveness.c @@ -30,8 +30,8 @@ void GC_start_world_external() g_assert_not_reached (); } #endif +#elif defined(HAVE_NULL_GC) #else -#error need to implement liveness GC API #endif custom_growable_array* array_create_and_initialize (guint capacity) @@ -634,6 +634,8 @@ void mono_unity_liveness_free_struct (LivenessState* state) g_free(state); } +void nullgc_unified_suspend_stop_world (); +void nullgc_unified_suspend_restart_world (); void mono_unity_liveness_stop_gc_world (LivenessState* state) { state->onWorldStopCallback(); @@ -641,6 +643,8 @@ void mono_unity_liveness_stop_gc_world (LivenessState* state) sgen_stop_world (1); #elif defined(HAVE_BOEHM_GC) GC_stop_world_external (); +#elif defined(HAVE_NULL_GC) + nullgc_unified_suspend_stop_world (); #else #error need to implement liveness GC API #endif @@ -652,6 +656,8 @@ void mono_unity_liveness_start_gc_world (LivenessState* state) sgen_restart_world (1); #elif defined(HAVE_BOEHM_GC) GC_start_world_external (); +#elif defined(HAVE_NULL_GC) + nullgc_unified_suspend_restart_world (); #else #error need to implement liveness GC API #endif diff --git a/mono/metadata/unity-memory-info.c b/mono/metadata/unity-memory-info.c index a7dab80c797b..2099bd014477 100644 --- a/mono/metadata/unity-memory-info.c +++ b/mono/metadata/unity-memory-info.c @@ -804,4 +804,10 @@ void mono_unity_free_captured_memory_snapshot(MonoManagedMemorySnapshot* snapsho g_free(snapshot); } +void +mono_unity_class_for_each (ClassReportFunc callback, void* user_data) +{ + +} + #endif \ No newline at end of file diff --git a/mono/metadata/unity-utils.c b/mono/metadata/unity-utils.c index d0ef772045c0..8280d8faa884 100644 --- a/mono/metadata/unity-utils.c +++ b/mono/metadata/unity-utils.c @@ -943,6 +943,7 @@ MONO_API void mono_unity_gc_set_mode(MonoGCMode mode) GC_set_disable_automatic_collection(TRUE); break; } +#elif defined(HAVE_NULL_GC) #else g_assert_not_reached (); #endif @@ -963,6 +964,7 @@ MONO_API void mono_unity_gc_disable() { #if HAVE_BDWGC_GC GC_disable(); +#elif defined(HAVE_NULL_GC) #else g_assert_not_reached (); #endif @@ -1852,11 +1854,15 @@ mono_unity_class_field_is_literal(MonoClassField *field) } // GC world control +void nullgc_unified_suspend_stop_world (); +void nullgc_unified_suspend_restart_world (); MONO_API void mono_unity_stop_gc_world() { #if HAVE_BDWGC_GC GC_stop_world_external(); +#elif defined(HAVE_NULL_GC) + nullgc_unified_suspend_stop_world (); #else g_assert_not_reached(); #endif @@ -1867,6 +1873,8 @@ mono_unity_start_gc_world() { #if HAVE_BDWGC_GC GC_start_world_external(); +#elif defined(HAVE_NULL_GC) + nullgc_unified_suspend_restart_world (); #else g_assert_not_reached(); #endif @@ -1893,6 +1901,7 @@ mono_unity_gc_heap_foreach(GFunc callback, gpointer user_data) ctx.user_data = user_data; GC_foreach_heap_section(&ctx, handle_gc_heap_chunk); +#elif defined(HAVE_NULL_GC) #else g_assert_not_reached(); #endif @@ -1914,6 +1923,7 @@ mono_unity_gc_handles_foreach_get_target(GFunc callback, gpointer user_data) ctx.callback = callback; ctx.user_data = user_data; mono_gc_strong_handle_foreach(handle_gc_handle, &ctx); +#elif defined(HAVE_NULL_GC) #else g_assert_not_reached(); #endif diff --git a/msvc/mono.props b/msvc/mono.props index b96720b8871a..303586d9738a 100644 --- a/msvc/mono.props +++ b/msvc/mono.props @@ -6,7 +6,7 @@ <!-- Change this to custom distribution tree location to enable out of source tree distribution, example c:/mono-dist/ --> <MONO_INSTALL_DIR_PREFIX>$(MSBuildProjectDirectory)/./dist/</MONO_INSTALL_DIR_PREFIX> <!-- GC in use, sgen or boehm, default is sgen. --> - <MONO_TARGET_GC>bdwgc</MONO_TARGET_GC> + <MONO_TARGET_GC>nullgc</MONO_TARGET_GC> <!-- When true, build targets will get a suffix based on used GC. Makes it possible to have builds using different GC's in same build folders, sharing common targets. --> <MONO_USE_TARGET_SUFFIX>true</MONO_USE_TARGET_SUFFIX> <!-- When true, build will get a separate build folder based on used GC. Makes it possible separate builds into different output folders under the same build prefix. --> @@ -62,6 +62,12 @@ <MONO_TARGET_SUFFIX Condition="'$(MONO_USE_TARGET_SUFFIX)'=='true'">-bdwgc</MONO_TARGET_SUFFIX> <MONO_BUILD_DIR_PREFIX Condition="'$(MONO_USE_SEPARATE_BUILD_DIR)'=='true'">$(MONO_BUILD_DIR_PREFIX)bdwgc/</MONO_BUILD_DIR_PREFIX> </PropertyGroup> + <PropertyGroup Label="NullGC" Condition="$(MONO_TARGET_GC)=='nullgc'"> + <GC_DEFINES>HAVE_NULL_GC</GC_DEFINES> + <GC_LIB></GC_LIB> + <MONO_TARGET_SUFFIX Condition="'$(MONO_USE_TARGET_SUFFIX)'=='true'">-nullgc</MONO_TARGET_SUFFIX> + <MONO_BUILD_DIR_PREFIX Condition="'$(MONO_USE_SEPARATE_BUILD_DIR)'=='true'">$(MONO_BUILD_DIR_PREFIX)nullgc/</MONO_BUILD_DIR_PREFIX> + </PropertyGroup> <PropertyGroup Label="Static-Mono-Libraries"> <MONO_RUNTIME_LIBS>libmonoutils.lib;libmonoruntime$(MONO_TARGET_SUFFIX).lib;libmini$(MONO_TARGET_SUFFIX).lib;$(GC_LIB)</MONO_RUNTIME_LIBS> <MONO_STATIC_LIBMONO_LIB>libmono-static$(MONO_TARGET_SUFFIX).lib</MONO_STATIC_LIBMONO_LIB>