⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 win32_threads.c

📁 Boost provides free peer-reviewed portable C++ source libraries. We emphasize libraries that work
💻 C
📖 第 1 页 / 共 4 页
字号:
#include "private/gc_priv.h"#if defined(GC_WIN32_THREADS)#include <windows.h>#ifdef THREAD_LOCAL_ALLOC# include "private/thread_local_alloc.h"#endif /* THREAD_LOCAL_ALLOC *//* Allocation lock declarations.	*/#if !defined(USE_PTHREAD_LOCKS)# if defined(GC_DLL)    __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;# else    CRITICAL_SECTION GC_allocate_ml;# endif  DWORD GC_lock_holder = NO_THREAD;  	/* Thread id for current holder of allocation lock */#else  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;  unsigned long GC_lock_holder = NO_THREAD;#endif#ifdef GC_PTHREADS# include <errno.h>/* GC_DLL should not normally be defined, especially since we often do turn *//* on THREAD_LOCAL_ALLOC, which is currently incompatible. 		    *//* It might be possible to get GC_DLL and DllMain-based	thread registration *//* to work with Cygwin, but if you try you are on your own.		    */#ifdef GC_DLL# error GC_DLL untested with Cygwin#endif /* Cygwin-specific forward decls */# undef pthread_create # undef pthread_sigmask # undef pthread_join # undef pthread_detach# undef dlopen # ifdef DEBUG_THREADS#   ifdef CYGWIN32#     define DEBUG_CYGWIN_THREADS 1#     define DEBUG_WIN32_PTHREADS 0#   else#     define DEBUG_WIN32_PTHREADS 1#     define DEBUG_CYGWIN_THREADS 0#   endif# else#   define DEBUG_CYGWIN_THREADS 0#   define DEBUG_WIN32_PTHREADS 0# endif  void * GC_pthread_start(void * arg);  void GC_thread_exit_proc(void *arg);# include <pthread.h>#else# ifdef DEBUG_THREADS#   define DEBUG_WIN32_THREADS 1# else#   define DEBUG_WIN32_THREADS 0# endif# undef CreateThread# undef ExitThread# undef _beginthreadex# undef _endthreadex# undef _beginthread# ifdef DEBUG_THREADS#   define DEBUG_WIN32_THREADS 1# else#   define DEBUG_WIN32_THREADS 0# endif# include <process.h>  /* For _beginthreadex, _endthreadex */#endif#if defined(GC_DLL) && !defined(MSWINCE)  static GC_bool GC_win32_dll_threads = FALSE;  /* This code operates in two distinct modes, depending on	*/  /* the setting of GC_win32_dll_threads.  If			*/  /* GC_win32_dll_threads is set, all threads in the process	*/  /* are implicitly registered with the GC by DllMain. 		*/  /* No explicit registration is required, and attempts at	*/  /* explicit registration are ignored.  This mode is		*/  /* very different from the Posix operation of the collector.	*/  /* In this mode access to the thread table is lock-free.	*/  /* Hence there is a static limit on the number of threads.	*/    /* If GC_win32_dll_threads is FALSE, or the collector is	*/  /* built without GC_DLL defined, things operate in a way	*/  /* that is very similar to Posix platforms, and new threads	*/  /* must be registered with the collector, e.g. by using	*/  /* preprocessor-based interception of the thread primitives.	*/  /* In this case, we use a real data structure for the thread	*/  /* table.  Note that there is no equivalent of linker-based	*/  /* call interception, since we don't have ELF-like 		*/  /* facilities.  The Windows analog appears to be "API		*/  /* hooking", which really seems to be a standard way to 	*/  /* do minor binary rewriting (?).  I'd prefer not to have	*/  /* the basic collector rely on such facilities, but an	*/  /* optional package that intercepts thread calls this way	*/  /* would probably be nice.					*/  /* GC_win32_dll_threads must be set at initialization time,	*/  /* i.e. before any collector or thread calls.  We make it a	*/  /* "dynamic" option only to avoid multiple library versions.	*/#else# define GC_win32_dll_threads FALSE#endif/* We have two versions of the thread table.  Which one	*//* we us depends on whether or not GC_win32_dll_threads *//* is set.  Note that before initialization, we don't 	*//* add any entries to either table, even if DllMain is	*//* called.  The main thread will be added on		*//* initialization.					*//* The type of the first argument to InterlockedExchange.	*//* Documented to be LONG volatile *, but at least gcc likes 	*//* this better.							*/typedef LONG * IE_t;GC_bool GC_thr_initialized = FALSE;GC_bool GC_need_to_lock = FALSE;static GC_bool parallel_initialized = FALSE;void GC_init_parallel(void);#ifdef GC_DLL  /* 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;  }#else  GC_API void GC_use_DllMain(void)  {      ABORT("GC not configured as DLL");  }#endifDWORD GC_main_thread = 0;struct GC_Thread_Rep {  union {    AO_t tm_in_use; 	/* Updated without lock.		*/  			/* We assert that unused 		*/  			/* entries have invalid ids of		*/  			/* zero and zero stack fields.  	*/    			/* Used only with GC_win32_dll_threads. */    struct GC_Thread_Rep * tm_next;    			/* Hash table link without 		*/    			/* GC_win32_dll_threads.		*/    			/* More recently allocated threads	*/			/* with a given pthread id come 	*/			/* first.  (All but the first are	*/			/* guaranteed to be dead, but we may    */			/* not yet have registered the join.)   */  } table_management;# define in_use table_management.tm_in_use# define next table_management.tm_next  DWORD id;  HANDLE handle;  ptr_t stack_base;	/* The cold end of the stack.   */			/* 0 ==> entry not valid.	*/			/* !in_use ==> stack_base == 0	*/  GC_bool suspended;# ifdef GC_PTHREADS    void *status; /* hold exit value until join in case it's a pointer */    pthread_t pthread_id;    short flags;		/* Protected by GC lock.	*/#	define FINISHED 1   	/* Thread has exited.	*/#	define DETACHED 2	/* Thread is intended to be detached.	*/#   define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)# else#   define KNOWN_FINISHED(t) 0# endif# ifdef THREAD_LOCAL_ALLOC    struct thread_local_freelists tlfs;# endif};typedef struct GC_Thread_Rep * GC_thread;typedef volatile struct GC_Thread_Rep * GC_vthread;/* * We assumed that volatile ==> memory ordering, at least among * volatiles.  This code should consistently use atomic_ops. */volatile GC_bool GC_please_stop = FALSE;/* * We track thread attachments while the world is supposed to be stopped. * Unfortunately, we can't stop them from starting, since blocking in * DllMain seems to cause the world to deadlock.  Thus we have to recover * If we notice this in the middle of marking. */AO_t GC_attached_thread = FALSE;/* Return TRUE if an thread was attached since we last asked or	*//* since GC_attached_thread was explicitly reset.		*/GC_bool GC_started_thread_while_stopped(void){  AO_t result;  if (GC_win32_dll_threads) {    AO_nop_full();	/* Prior heap reads need to complete earlier. */    result = AO_load(&GC_attached_thread);    if (result) {      AO_store(&GC_attached_thread, FALSE);    }    return ((GC_bool)result);  } else {    return FALSE;  }}/* Thread table used if GC_win32_dll_threads is set.	*//* This is a fixed size array.				*//* Since we use runtime conditionals, both versions	*//* are always defined.					*/# ifndef MAX_THREADS#   define MAX_THREADS 512#  endif  /* Things may get quite slow for large numbers of threads,	*/  /* since we look them up with sequential search.		*/  volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];  volatile LONG GC_max_thread_index = 0;  			/* Largest index in dll_thread_table	*/		        /* that was ever used.			*//* And now the version used if GC_win32_dll_threads is not set.	*//* This is a chained hash table, with much of the code borrowed	*//* From the Posix implementation.				*/# define THREAD_TABLE_SZ 256	/* Must be power of 2	*/  GC_thread GC_threads[THREAD_TABLE_SZ];  /* Add a thread to GC_threads.  We assume it wasn't already there.	*//* Caller holds allocation lock.					*//* Unlike the pthreads version, the id field is set by the caller.	*/GC_thread GC_new_thread(DWORD id){    word hv = ((word)id) % THREAD_TABLE_SZ;    GC_thread result;    /* It may not be safe to allocate when we register the first thread. */    static struct GC_Thread_Rep first_thread;    static GC_bool first_thread_used = FALSE;        GC_ASSERT(I_HOLD_LOCK());    if (!first_thread_used) {    	result = &first_thread;    	first_thread_used = TRUE;    } else {        GC_ASSERT(!GC_win32_dll_threads);        result = (struct GC_Thread_Rep *)        	 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);#       ifdef GC_PTHREADS	  /* result can be NULL -> segfault */	  GC_ASSERT(result -> flags == 0);#       endif    }    if (result == 0) return(0);    /* result -> id = id; Done by caller.	*/    result -> next = GC_threads[hv];    GC_threads[hv] = result;#   ifdef GC_PTHREADS      GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);#   endif    return(result);}extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);#if defined(GWW_VDB) && defined(MPROTECT_VDB)  extern GC_bool GC_gww_dirty_init(void);  /* Defined in os_dep.c.  Returns TRUE if GetWriteWatch is available. 	*/  /* may be called repeatedly.						*/#endifGC_bool GC_in_thread_creation = FALSE;  /* Protected by allocation lock. *//* * This may be called from DllMain, and hence operates under unusual * constraints.  In particular, it must be lock-free if GC_win32_dll_threads * is set.  Always called from the thread being added. * If GC_win32_dll_threads is not set, we already hold the allocation lock, * except possibly during single-threaded start-up code. */static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,					     DWORD thread_id){  GC_vthread me;  /* 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 defined(GWW_VDB)      if (GC_incremental && !GC_gww_dirty_init())	SetUnhandledExceptionFilter(GC_write_fault_handler);#   else      if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);#   endif# endif  if (GC_win32_dll_threads) {    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.		*/    /* It has been claimed that DllMain is really only executed with	*/    /* a particular system lock held, and thus careful use of locking	*/    /* around code that doesn't call back into the system libraries	*/    /* might be OK.  But this hasn't been tested across all win32	*/    /* variants.							*/                /* cast away volatile qualifier */    for (i = 0; InterlockedExchange((IE_t)&dll_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.							*/      /* FIXME: We should eventually declare Win95 dead and use AO_	*/      /* primitives 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;    }    me = dll_thread_table + i;  } else /* Not using DllMain */ {    GC_ASSERT(I_HOLD_LOCK());    GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */    me = GC_new_thread(thread_id);    GC_in_thread_creation = FALSE;  }# ifdef GC_PTHREADS    /* me can be NULL -> segfault */    me -> pthread_id = pthread_self();# endif  if (!DuplicateHandle(GetCurrentProcess(),                 	GetCurrentThread(),		        GetCurrentProcess(),		        (HANDLE*)&(me -> handle),		        0,		        0,		        DUPLICATE_SAME_ACCESS)) {	DWORD last_error = GetLastError();	GC_err_printf("Last error code: %d\n", last_error);	ABORT("DuplicateHandle failed");  }  me -> stack_base = sb -> mem_base;  /* Up until this point, GC_push_all_stacks considers this thread	*/  /* invalid.								*/  /* Up until this point, this entry is viewed as reserved but invalid	*/  /* by GC_delete_thread.						*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -