/* Turn on GC_win32_dll_threads */ GC_API void GC_use_DllMain(void) { # ifdef THREAD_LOCAL_ALLOC ABORT("Cannot use thread local allocation with DllMain-based " "thread registration."); /* Thread-local allocation really wants to lock at thread */ /* entry and exit. */ # endif GC_ASSERT(!parallel_initialized); GC_win32_dll_threads = TRUE; GC_init_parallel(); }
int GC_pthread_join(pthread_t pthread_id, void **retval) { int result; int i; GC_thread joinee; # if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); # endif # if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n", (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p); # endif if (!parallel_initialized) GC_init_parallel(); /* Thread being joined might not have registered itself yet. */ /* After the join,thread id may have been recycled. */ /* FIXME: It would be better if this worked more like */ /* pthread_support.c. */ #ifndef GC_WIN32_PTHREADS while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10); #endif result = pthread_join(pthread_id, retval); #ifdef GC_WIN32_PTHREADS /* win32_pthreads id are unique */ joinee = GC_lookup_pthread(pthread_id); #endif if (!GC_win32_dll_threads) { LOCK(); GC_delete_gc_thread(joinee); UNLOCK(); } /* otherwise dllmain handles it. */ # if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); # endif # if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n", (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p); # endif return result; }
GC_PTR GC_local_malloc(size_t bytes) { if (EXPECT(!SMALL_ENOUGH(bytes),0)) { return(GC_malloc(bytes)); } else { int index = INDEX_FROM_BYTES(bytes); ptr_t * my_fl; ptr_t my_entry; # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) GC_key_t k = GC_thread_key; # endif void * tsd; # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) if (EXPECT(0 == k, 0)) { /* This can happen if we get called when the world is */ /* being initialized. Whether we can actually complete */ /* the initialization then is unclear. */ GC_init_parallel(); k = GC_thread_key; } # endif tsd = GC_getspecific(GC_thread_key); # ifdef GC_ASSERTIONS LOCK(); GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self())); UNLOCK(); # endif my_fl = ((GC_thread)tsd) -> normal_freelists + index; my_entry = *my_fl; if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { ptr_t next = obj_link(my_entry); GC_PTR result = (GC_PTR)my_entry; *my_fl = next; obj_link(my_entry) = 0; PREFETCH_FOR_WRITE(next); return result; } else if ((word)my_entry - 1 < DIRECT_GRANULES) { *my_fl = my_entry + index + 1; return GC_malloc(bytes); } else { GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl); if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_malloc(bytes); } } }
/* Cygwin-pthreads calls CreateThread internally, but it's not * easily interceptible by us.. * so intercept pthread_create instead */ int GC_pthread_create(pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { int result; struct start_info * si; if (!parallel_initialized) GC_init_parallel(); /* make sure GC is initialized (i.e. main thread is attached) */ if (GC_win32_dll_threads) { return pthread_create(new_thread, attr, start_routine, arg); } /* This is otherwise saved only in an area mmapped by the thread */ /* library, which isn't visible to the collector. */ si = GC_malloc_uncollectable(sizeof(struct start_info)); if (0 == si) return(EAGAIN); si -> start_routine = start_routine; si -> arg = arg; if (attr != 0 && pthread_attr_getdetachstate(attr, &si->detached) == PTHREAD_CREATE_DETACHED) { si->detached = TRUE; } # if DEBUG_CYGWIN_THREADS GC_printf("About to create a thread from 0x%x(0x%x)\n", (int)pthread_self(), GetCurrentThreadId); # endif # if DEBUG_WIN32_PTHREADS GC_printf("About to create a thread from 0x%x(0x%x)\n", (int)(pthread_self()).p, GetCurrentThreadId()); # endif GC_need_to_lock = TRUE; result = pthread_create(new_thread, attr, GC_pthread_start, si); if (result) { /* failure */ GC_free(si); } return(result); }
int GC_pthread_detach(pthread_t thread) { int result; GC_thread thread_gc_id; if (!parallel_initialized) GC_init_parallel(); LOCK(); thread_gc_id = GC_lookup_pthread(thread); UNLOCK(); result = pthread_detach(thread); if (result == 0) { LOCK(); thread_gc_id -> flags |= DETACHED; /* Here the pthread thread id may have been recycled. */ if (thread_gc_id -> flags & FINISHED) { GC_delete_gc_thread(thread_gc_id); } UNLOCK(); } return result; }
GC_API HANDLE WINAPI GC_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) { HANDLE thread_h = NULL; thread_args *args; if (!parallel_initialized) GC_init_parallel(); /* make sure GC is initialized (i.e. main thread is attached, tls initialized) */ # if DEBUG_WIN32_THREADS GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId()); # endif if (GC_win32_dll_threads) { return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId); } else { args = GC_malloc_uncollectable(sizeof(thread_args)); /* Handed off to and deallocated by child thread. */ if (0 == args) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } /* set up thread arguments */ args -> start = lpStartAddress; args -> param = lpParameter; GC_need_to_lock = TRUE; thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start, args, dwCreationFlags, lpThreadId); if( thread_h == 0 ) GC_free( args ); return thread_h; } }
uintptr_t GC_beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr) { uintptr_t thread_h; thread_args *args; if (!parallel_initialized) GC_init_parallel(); /* make sure GC is initialized (i.e. main thread is attached, tls initialized) */ # if DEBUG_WIN32_THREADS GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId()); # endif if (GC_win32_dll_threads) { return _beginthreadex(security, stack_size, start_address, arglist, initflag, thrdaddr); } else { args = GC_malloc_uncollectable(sizeof(thread_args)); /* Handed off to and deallocated by child thread. */ if (0 == args) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return (uintptr_t)(-1L); } /* set up thread arguments */ args -> start = (LPTHREAD_START_ROUTINE)start_address; args -> param = arglist; GC_need_to_lock = TRUE; thread_h = _beginthreadex(security, stack_size, (unsigned (__stdcall *) (void *))GC_win32_start, args, initflag, thrdaddr); if( thread_h == 0 ) GC_free( args ); return thread_h; } }
/* nothing required here... */ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { if (!parallel_initialized) GC_init_parallel(); return pthread_sigmask(how, set, oset); }