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

📄 win32_threads.c

📁 Boost provides free peer-reviewed portable C++ source libraries. We emphasize libraries that work
💻 C
📖 第 1 页 / 共 4 页
字号:
  me -> id = thread_id;# if defined(THREAD_LOCAL_ALLOC)      GC_init_thread_local((GC_tlfs)(&(me->tlfs)));# endif  if (me -> stack_base == NULL)       ABORT("Bad stack base in GC_register_my_thread_inner");  if (GC_win32_dll_threads) {    if (GC_please_stop) {      AO_store(&GC_attached_thread, TRUE);      AO_nop_full();  // Later updates must become visible after this.    }    /* We'd like to wait here, but can't, since waiting in DllMain 	*/    /* provokes deadlocks.						*/    /* Thus we force marking to be restarted instead.			*/  } else {    GC_ASSERT(!GC_please_stop);  	/* Otherwise both we and the thread stopping code would be	*/  	/* holding the allocation lock.					*/  }  return (GC_thread)(me);}/* * GC_max_thread_index may temporarily be larger than MAX_THREADS. * To avoid subscript errors, we check on access. */#ifdef __GNUC____inline__#endifLONG GC_get_max_thread_index(){  LONG my_max = GC_max_thread_index;  if (my_max >= MAX_THREADS) return MAX_THREADS-1;  return my_max;}/* Return the GC_thread corresponding to a thread id.  May be called 	*//* without a lock, but should be called in contexts in which the	*//* requested thread cannot be asynchronously deleted, e.g. from the	*//* thread itself.							*//* This version assumes that either GC_win32_dll_threads is set, or	*//* we hold the allocator lock.						*//* Also used (for assertion checking only) from thread_local_alloc.c.	*/GC_thread GC_lookup_thread_inner(DWORD thread_id) {  if (GC_win32_dll_threads) {    int i;    LONG my_max = GC_get_max_thread_index();    for (i = 0;       i <= my_max &&       (!AO_load_acquire(&(dll_thread_table[i].in_use))	|| dll_thread_table[i].id != thread_id);       /* Must still be in_use, since nobody else can store our thread_id. */       i++) {}    if (i > my_max) {      return 0;    } else {      return (GC_thread)(dll_thread_table + i);    }  } else {    word hv = ((word)thread_id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];        GC_ASSERT(I_HOLD_LOCK());    while (p != 0 && p -> id != thread_id) p = p -> next;    return(p);  }}/* A version of the above that acquires the lock if necessary.  Note	*//* that the identically named function for pthreads is different, and	*//* just assumes we hold the lock.					*//* Also used (for assertion checking only) from thread_local_alloc.c.	*/static GC_thread GC_lookup_thread(DWORD thread_id){  if (GC_win32_dll_threads) {    return GC_lookup_thread_inner(thread_id);  } else {    GC_thread result;    LOCK();    result = GC_lookup_thread_inner(thread_id);    UNLOCK();    return result;  }}/* If a thread has been joined, but we have not yet		*//* been notified, then there may be more than one thread 	*//* in the table with the same win32 id.				*//* This is OK, but we need a way to delete a specific one.	*//* Assumes we hold the allocation lock unless			*//* GC_win32_dll_threads is set.					*//* If GC_win32_dll_threads is set it should be called from the	*//* thread being deleted.					*/void GC_delete_gc_thread(GC_vthread gc_id){  if (GC_win32_dll_threads) {    /* This is intended to be lock-free.				*/    /* It is either called synchronously from the thread being deleted,	*/    /* or by the joining thread.					*/    /* In this branch asynchronosu changes to *gc_id are possible.	*/    CloseHandle(gc_id->handle);    gc_id -> stack_base = 0;    gc_id -> id = 0;#   ifdef CYGWIN32      gc_id -> pthread_id = 0;#   endif /* CYGWIN32 */#   ifdef GC_WIN32_PTHREADS      gc_id -> pthread_id.p = NULL;#   endif /* GC_WIN32_PTHREADS */    AO_store_release(&(gc_id->in_use), FALSE);  } else {    /* Cast away volatile qualifier, since we have lock. */    GC_thread gc_nvid = (GC_thread)gc_id;    DWORD id = gc_nvid -> id;    word hv = ((word)id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];    register GC_thread prev = 0;    GC_ASSERT(I_HOLD_LOCK());    while (p != gc_nvid) {        prev = p;        p = p -> next;    }    if (prev == 0) {        GC_threads[hv] = p -> next;    } else {        prev -> next = p -> next;    }    GC_INTERNAL_FREE(p);  }}/* Delete a thread from GC_threads.  We assume it is there.	*//* (The code intentionally traps if it wasn't.)			*//* Assumes we hold the allocation lock unless			*//* GC_win32_dll_threads is set.					*//* If GC_win32_dll_threads is set it should be called from the	*//* thread being deleted.					*/void GC_delete_thread(DWORD id){  if (GC_win32_dll_threads) {    GC_thread t = GC_lookup_thread_inner(id);    if (0 == t) {      WARN("Removing nonexistent thread %ld\n", (GC_word)id);    } else {      GC_delete_gc_thread(t);    }  } else {    word hv = ((word)id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];    register GC_thread prev = 0;        GC_ASSERT(I_HOLD_LOCK());    while (p -> id != id) {        prev = p;        p = p -> next;    }    if (prev == 0) {        GC_threads[hv] = p -> next;    } else {        prev -> next = p -> next;    }    GC_INTERNAL_FREE(p);  }}int GC_register_my_thread(struct GC_stack_base *sb) {  DWORD t = GetCurrentThreadId();  if (0 == GC_lookup_thread(t)) {    /* We lock here, since we want to wait for an ongoing GC.	*/    LOCK();    GC_register_my_thread_inner(sb, t);    UNLOCK();    return GC_SUCCESS;  } else {    return GC_DUPLICATE;  }}int GC_unregister_my_thread(void){    DWORD t = GetCurrentThreadId();#   if defined(THREAD_LOCAL_ALLOC)      LOCK();      {	GC_thread me = GC_lookup_thread_inner(t);        GC_destroy_thread_local(&(me->tlfs));      }      UNLOCK();#   endif    if (GC_win32_dll_threads) {      /* Should we just ignore this? */      GC_delete_thread(t);    } else {      LOCK();      GC_delete_thread(t);      UNLOCK();    }    return GC_SUCCESS;}#ifdef GC_PTHREADS/* A quick-and-dirty cache of the mapping between pthread_t	*//* and win32 thread id.						*/#define PTHREAD_MAP_SIZE 512DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE];#define HASH(pthread_id) ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)	/* It appears pthread_t is really a pointer type ... */#define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \	GC_pthread_map_cache[HASH(pthread_id)] = (win32_id);#define GET_PTHREAD_MAP_CACHE(pthread_id) \	GC_pthread_map_cache[HASH(pthread_id)]/* Return a GC_thread corresponding to a given pthread_t.	*//* Returns 0 if it's not there.					*//* We assume that this is only called for pthread ids that	*//* have not yet terminated or are still joinable, and		*//* cannot be concurrently terminated.				*//* Assumes we do NOT hold the allocation lock.			*/static GC_thread GC_lookup_pthread(pthread_t id){  if (GC_win32_dll_threads) {    int i;    LONG my_max = GC_get_max_thread_index();    for (i = 0;         i <= my_max &&         (!AO_load_acquire(&(dll_thread_table[i].in_use))	  || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));       /* Must still be in_use, since nobody else can store our thread_id. */       i++);    if (i > my_max) return 0;    return (GC_thread)(dll_thread_table + i);  } else {    /* We first try the cache.  If that fails, we use a very slow	*/    /* approach.							*/    int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ;    int hv;    GC_thread p;    LOCK();    for (p = GC_threads[hv_guess]; 0 != p; p = p -> next) {      if (THREAD_EQUAL(p -> pthread_id, id))	goto foundit;     }    for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {      for (p = GC_threads[hv]; 0 != p; p = p -> next) {        if (THREAD_EQUAL(p -> pthread_id, id))	  goto foundit;       }    }    p = 0;   foundit:    UNLOCK();    return p;  }}#endif /* GC_PTHREADS */void GC_push_thread_structures(void){  GC_ASSERT(I_HOLD_LOCK());  if (GC_win32_dll_threads) {    /* Unlike the other threads implementations, the thread table here	*/    /* contains no pointers to the collectable heap.  Thus we have	*/    /* no private structures we need to preserve.			*/#   ifdef GC_PTHREADS     { int i; /* pthreads may keep a pointer in the thread exit value */      LONG my_max = GC_get_max_thread_index();      for (i = 0; i <= my_max; i++)        if (dll_thread_table[i].in_use)	  GC_push_all((ptr_t)&(dll_thread_table[i].status),                      (ptr_t)(&(dll_thread_table[i].status)+1));    }#   endif  } else {    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));  }# if defined(THREAD_LOCAL_ALLOC)    GC_push_all((ptr_t)(&GC_thread_key),      (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));    /* Just in case we ever use our own TLS implementation.	*/# endif}/* Suspend the given thread, if it's still active.	*/void GC_suspend(GC_thread t){# ifdef MSWINCE    /* SuspendThread will fail if thread is running kernel code */      while (SuspendThread(t -> handle) == (DWORD)-1)	Sleep(10);# else    /* Apparently the Windows 95 GetOpenFileName call creates	*/    /* a thread that does not properly get cleaned up, and		*/    /* SuspendThread on its descriptor may provoke a crash.		*/    /* This reduces the probability of that event, though it still	*/    /* appears there's a race here.					*/    DWORD exitCode;     if (GetExitCodeThread(t -> handle, &exitCode) &&        exitCode != STILL_ACTIVE) {      t -> stack_base = 0; /* prevent stack from being pushed */#     ifndef GC_PTHREADS        /* this breaks pthread_join on Cygwin, which is guaranteed to  */        /* only see user pthreads 	 			       */        AO_store(&(t -> in_use), FALSE);        CloseHandle(t -> handle);#     endif      return;    }    if (SuspendThread(t -> handle) == (DWORD)-1)      ABORT("SuspendThread failed");# endif   t -> suspended = TRUE;}/* Defined in misc.c */#ifndef CYGWIN32  extern CRITICAL_SECTION GC_write_cs;#endifvoid GC_stop_world(void){  DWORD thread_id = GetCurrentThreadId();  int i;  if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");  GC_ASSERT(I_HOLD_LOCK());  GC_please_stop = TRUE;# ifndef CYGWIN32    EnterCriticalSection(&GC_write_cs);# endif  if (GC_win32_dll_threads) {    /* Any threads being created during this loop will end up setting   */    /* GC_attached_thread when they start.  This will force marking to  */    /* restart.								*/    /* This is not ideal, but hopefully correct.			*/    GC_attached_thread = FALSE;    for (i = 0; i <= GC_get_max_thread_index(); i++) {      GC_vthread t = dll_thread_table + i;      if (t -> stack_base != 0	  && t -> id != thread_id) {	  GC_suspend((GC_thread)t);      }    }  } else {      GC_thread t;      int i;      for (i = 0; i < THREAD_TABLE_SZ; i++) {        for (t = GC_threads[i]; t != 0; t = t -> next) {	  if (t -> stack_base != 0	  && !KNOWN_FINISHED(t)	  && t -> id != thread_id) {	    GC_suspend(t);	  }	}      }  }# ifndef CYGWIN32    LeaveCriticalSection(&GC_write_cs);# endif    }void GC_start_world(void){  DWORD thread_id = GetCurrentThreadId();  int i;  LONG my_max = GC_get_max_thread_index();  GC_ASSERT(I_HOLD_LOCK());  if (GC_win32_dll_threads) {    for (i = 0; i <= my_max; i++) {      GC_thread t = (GC_thread)(dll_thread_table + i);      if (t -> stack_base != 0 && t -> suspended	  && t -> id != thread_id) {        if (ResumeThread(t -> handle) == (DWORD)-1)	  ABORT("ResumeThread failed");        t -> suspended = FALSE;      }    }  } else {    GC_thread t;    int i;

⌨️ 快捷键说明

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