gboolean mono_gc_register_thread (void *baseptr) { #if GC_VERSION_MAJOR >= 7 struct GC_stack_base sb; int res; res = GC_get_stack_base (&sb); if (res != GC_SUCCESS) { sb.mem_base = baseptr; #ifdef __ia64__ /* Can't determine the register stack bounds */ g_error ("mono_gc_register_thread failed ().\n"); #endif } res = GC_register_my_thread (&sb); if ((res != GC_SUCCESS) && (res != GC_DUPLICATE)) { g_warning ("GC_register_my_thread () failed.\n"); return FALSE; } return TRUE; #else if (mono_gc_is_gc_thread()) return TRUE; #if defined(USE_INCLUDED_LIBGC) && !defined(PLATFORM_WIN32) return GC_thread_register_foreign (baseptr); #else return FALSE; #endif #endif }
static void* boehm_thread_register (MonoThreadInfo* info, void *baseptr) { #if GC_VERSION_MAJOR >= 7 struct GC_stack_base sb; int res; res = GC_get_stack_base (&sb); if (res != GC_SUCCESS) { sb.mem_base = baseptr; #ifdef __ia64__ /* Can't determine the register stack bounds */ g_error ("mono_gc_register_thread failed ().\n"); #endif } res = GC_register_my_thread (&sb); if ((res != GC_SUCCESS) && (res != GC_DUPLICATE)) { g_warning ("GC_register_my_thread () failed.\n"); return NULL; } return info; #else if (mono_gc_is_gc_thread()) return info; #if defined(USE_INCLUDED_LIBGC) && !defined(HOST_WIN32) return GC_thread_register_foreign (baseptr) ? info : NULL; #else return NULL; #endif #endif }
extern unsigned long scheme_get_stack_base() { #if !defined(MZ_PRECISE_GC) && !defined(USE_SENORA_GC) if (GC_stackbottom) return (unsigned long)GC_stackbottom; else #endif return (unsigned long)GC_get_stack_base(); }
GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) { struct GC_stack_base sb; DWORD thread_id; int sb_result; static int entry_count = 0; if (parallel_initialized && !GC_win32_dll_threads) return TRUE; switch (reason) { case DLL_THREAD_ATTACH: GC_ASSERT(entry_count == 0 || parallel_initialized); ++entry_count; /* and fall through: */ case DLL_PROCESS_ATTACH: /* This may run with the collector uninitialized. */ thread_id = GetCurrentThreadId(); if (parallel_initialized && GC_main_thread != thread_id) { /* Don't lock here. */ sb_result = GC_get_stack_base(&sb); GC_ASSERT(sb_result == GC_SUCCESS); # ifdef THREAD_LOCAL_ALLOC ABORT("Cannot initialize thread local cache from DllMain"); # endif GC_register_my_thread_inner(&sb, thread_id); } /* o.w. we already did it during GC_thr_init(), called by GC_init() */ break; case DLL_THREAD_DETACH: /* We are hopefully running in the context of the exiting thread. */ GC_ASSERT(parallel_initialized); if (!GC_win32_dll_threads) return TRUE; GC_delete_thread(GetCurrentThreadId()); break; case DLL_PROCESS_DETACH: { int i; if (!GC_win32_dll_threads) return TRUE; for (i = 0; i <= GC_get_max_thread_index(); ++i) { if (AO_load(&(dll_thread_table[i].in_use))) GC_delete_gc_thread(dll_thread_table + i); } GC_deinit(); DeleteCriticalSection(&GC_allocate_ml); } break; } return TRUE; }
/* At the start of a thread other than the main thread, we need to register the new thread with the collector. */ static void conservative_thread_start() { struct GC_stack_base sb; if(GC_get_stack_base(&sb) != GC_SUCCESS) { fprintf(stderr, "Failure getting stack base for interpreter thread.\n"); exit(EXIT_FAILURE); } if(GC_register_my_thread(&sb) != GC_SUCCESS) { fprintf(stderr, "Failure registering interpreter thread.\n"); exit(EXIT_FAILURE); } }
/* Called by GC_init() - we hold the allocation lock. */ void GC_thr_init(void) { struct GC_stack_base sb; int sb_result; GC_ASSERT(I_HOLD_LOCK()); if (GC_thr_initialized) return; GC_main_thread = GetCurrentThreadId(); GC_thr_initialized = TRUE; /* Add the initial thread, so we can stop it. */ sb_result = GC_get_stack_base(&sb); GC_ASSERT(sb_result == GC_SUCCESS); GC_register_my_thread(&sb); }
EXTERN bool neko_thread_register( bool t ) { # if !defined(NEKO_THREADS) return 0; # elif defined(NEKO_WINDOWS) struct GC_stack_base sb; int r; if( !t ) return GC_unregister_my_thread() == GC_SUCCESS; if( GC_get_stack_base(&sb) != GC_SUCCESS ) return 0; r = GC_register_my_thread(&sb); return( r == GC_SUCCESS || r == GC_DUPLICATE ); # else // since the API is only available on GC 7.0, // we will do our best to locate it dynamically static gc_stack_ptr get_sb = NULL, my_thread = NULL; static std_func unreg_my_thread = NULL; if( !t && unreg_my_thread != NULL ) { return unreg_my_thread() == GC_SUCCESS; } else if( my_thread != NULL ) { __stack_base sb; int r; if( get_sb(&sb) != GC_SUCCESS ) return 0; r = my_thread(&sb); return( r == GC_SUCCESS || r == GC_DUPLICATE ); } else { void *self = dlopen(NULL,0); my_thread = (gc_stack_ptr)dlsym(self,"GC_register_my_thread"); get_sb = (gc_stack_ptr)dlsym(self,"GC_get_stack_base"); unreg_my_thread = (std_func)dlsym(self,"GC_unregister_my_thread"); if( my_thread == NULL ) my_thread = do_nothing; if( get_sb == NULL ) get_sb = do_nothing; if( unreg_my_thread == NULL ) unreg_my_thread = (std_func)do_nothing; return neko_thread_register(t); } # endif }
/* * This may be called from DllMain, and hence operates under unusual * constraints. */ static GC_thread GC_new_thread(void) { int i; /* It appears to be unsafe to acquire a lock here, since this */ /* code is apparently not preeemptible on some systems. */ /* (This is based on complaints, not on Microsoft's official */ /* documentation, which says this should perform "only simple */ /* initialization tasks".) */ /* Hence we make do with nonblocking synchronization. */ /* The following should be a noop according to the win32 */ /* documentation. There is empirical evidence that it */ /* isn't. - HB */ # if defined(MPROTECT_VDB) if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); # endif /* cast away volatile qualifier */ for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) { /* Compare-and-swap would make this cleaner, but that's not */ /* supported before Windows 98 and NT 4.0. In Windows 2000, */ /* InterlockedExchange is supposed to be replaced by */ /* InterlockedExchangePointer, but that's not really what I */ /* want here. */ if (i == MAX_THREADS - 1) ABORT("too many threads"); } /* Update GC_max_thread_index if necessary. The following is safe, */ /* and unlike CompareExchange-based solutions seems to work on all */ /* Windows95 and later platforms. */ /* Unfortunately, GC_max_thread_index may be temporarily out of */ /* bounds, so readers have to compensate. */ while (i > GC_max_thread_index) { InterlockedIncrement((IE_t)&GC_max_thread_index); } if (GC_max_thread_index >= MAX_THREADS) { /* We overshot due to simultaneous increments. */ /* Setting it to MAX_THREADS-1 is always safe. */ GC_max_thread_index = MAX_THREADS - 1; } # ifdef CYGWIN32 thread_table[i].pthread_id = pthread_self(); # endif if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), (HANDLE*)&thread_table[i].handle, 0, 0, DUPLICATE_SAME_ACCESS)) { DWORD last_error = GetLastError(); GC_printf1("Last error code: %lx\n", last_error); ABORT("DuplicateHandle failed"); } thread_table[i].stack_base = GC_get_stack_base(); /* Up until this point, GC_push_all_stacks considers this thread */ /* invalid. */ if (thread_table[i].stack_base == NULL) ABORT("Failed to find stack base in GC_new_thread"); /* Up until this point, this entry is viewed as reserved but invalid */ /* by GC_delete_thread. */ thread_table[i].id = GetCurrentThreadId(); /* If this thread is being created while we are trying to stop */ /* the world, wait here. Hopefully this can't happen on any */ /* systems that don't allow us to block here. */ while (GC_please_stop) Sleep(20); GC_ASSERT(!thread_table[i]->thread_blocked); return thread_table + i; }