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

📄 win32_threads.c

📁 linux下建立JAVA虚拟机的源码KAFFE
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "private/gc_priv.h"#if defined(GC_WIN32_THREADS) #include <windows.h>#ifdef CYGWIN32# include <errno.h> /* Cygwin-specific forward decls */# undef pthread_create # undef pthread_sigmask # undef pthread_join # undef pthread_detach# undef dlopen # define DEBUG_CYGWIN_THREADS 0  void * GC_start_routine(void * arg);  void GC_thread_exit_proc(void *arg);#endif/* The type of the first argument to InterlockedExchange.	*//* Documented to be LONG volatile *, but at least gcc likes 	*//* this better.							*/typedef LONG * IE_t;#ifndef MAX_THREADS# define MAX_THREADS 256    /* FIXME:							*/    /* Things may get quite slow for large numbers of threads,	*/    /* since we look them up with sequential search.		*/#endifGC_bool GC_thr_initialized = FALSE;DWORD GC_main_thread = 0;struct GC_thread_Rep {  LONG in_use; /* Updated without lock.	*/  			/* We assert that unused 	*/  			/* entries have invalid ids of	*/  			/* zero and zero stack fields.  */  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 CYGWIN32    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.	*/# endif};typedef volatile struct GC_thread_Rep * GC_thread;/* * We generally assume that volatile ==> memory ordering, at least among * volatiles. */volatile GC_bool GC_please_stop = FALSE;volatile struct GC_thread_Rep thread_table[MAX_THREADS];volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table	*/				       /* that was ever used.		*/extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);/* * 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);  return thread_table + i;}/* * 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;}/* This is intended to be lock-free, though that			*//* assumes that the CloseHandle becomes visible before the 		*//* in_use assignment.							*/static void GC_delete_gc_thread(GC_thread thr){    CloseHandle(thr->handle);      /* cast away volatile qualifier */    thr->stack_base = 0;    thr->id = 0;#   ifdef CYGWIN32      thr->pthread_id = 0;#   endif /* CYGWIN32 */    thr->in_use = FALSE;}static void GC_delete_thread(DWORD thread_id) {  int i;  LONG my_max = GC_get_max_thread_index();  for (i = 0;       i <= my_max &&       (!thread_table[i].in_use || thread_table[i].id != thread_id);       /* Must still be in_use, since nobody else can store our thread_id. */       i++) {}  if (i > my_max) {    WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id);  } else {    GC_delete_gc_thread(thread_table+i);  }}#ifdef CYGWIN32/* 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.		*/static GC_thread GC_lookup_thread(pthread_t id){  int i;  LONG my_max = GC_get_max_thread_index();  for (i = 0;       i <= my_max &&       (!thread_table[i].in_use || thread_table[i].pthread_id != id	|| !thread_table[i].in_use);       /* Must still be in_use, since nobody else can store our thread_id. */       i++);  if (i > my_max) return 0;  return thread_table + i;}#endif /* CYGWIN32 */void GC_push_thread_structures GC_PROTO((void)){    /* 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 CYGWIN32  { 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 (thread_table[i].in_use)	GC_push_all((ptr_t)&(thread_table[i].status),                    (ptr_t)(&(thread_table[i].status)+1));  }# endif}/* Defined in misc.c */extern CRITICAL_SECTION GC_write_cs;void GC_stop_world(){  DWORD thread_id = GetCurrentThreadId();  int i;  if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");  GC_please_stop = TRUE;# ifndef CYGWIN32    EnterCriticalSection(&GC_write_cs);# endif /* !CYGWIN32 */  for (i = 0; i <= GC_get_max_thread_index(); i++)    if (thread_table[i].stack_base != 0	&& thread_table[i].id != thread_id) {#     ifdef MSWINCE        /* SuspendThread will fail if thread is running kernel code */	while (SuspendThread(thread_table[i].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(thread_table[i].handle,&exitCode) &&            exitCode != STILL_ACTIVE) {          thread_table[i].stack_base = 0; /* prevent stack from being pushed */#         ifndef CYGWIN32            /* this breaks pthread_join on Cygwin, which is guaranteed to  */	    /* only see user pthreads 					   */	    thread_table[i].in_use = FALSE;	    CloseHandle(thread_table[i].handle);#         endif	  continue;	}	if (SuspendThread(thread_table[i].handle) == (DWORD)-1)	  ABORT("SuspendThread failed");#     endif      thread_table[i].suspended = TRUE;    }# ifndef CYGWIN32    LeaveCriticalSection(&GC_write_cs);# endif /* !CYGWIN32 */}void GC_start_world(){  DWORD thread_id = GetCurrentThreadId();  int i;  LONG my_max = GC_get_max_thread_index();  for (i = 0; i <= my_max; i++)    if (thread_table[i].stack_base != 0 && thread_table[i].suspended	&& thread_table[i].id != thread_id) {      if (ResumeThread(thread_table[i].handle) == (DWORD)-1)	ABORT("ResumeThread failed");      thread_table[i].suspended = FALSE;    }  GC_please_stop = FALSE;}# ifdef _MSC_VER#   pragma warning(disable:4715)# endifptr_t GC_current_stackbottom(){  DWORD thread_id = GetCurrentThreadId();  int i;  LONG my_max = GC_get_max_thread_index();  for (i = 0; i <= my_max; i++)    if (thread_table[i].stack_base && thread_table[i].id == thread_id)      return thread_table[i].stack_base;  ABORT("no thread table entry for current thread");}# ifdef _MSC_VER#   pragma warning(default:4715)# endif# ifdef MSWINCE    /* The VirtualQuery calls below won't work properly on WinCE, but	*/    /* since each stack is restricted to an aligned 64K region of	*/    /* virtual memory we can just take the next lowest multiple of 64K.	*/#   define GC_get_stack_min(s) \        ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))# else    static ptr_t GC_get_stack_min(ptr_t s)    {	ptr_t bottom;	MEMORY_BASIC_INFORMATION info;	VirtualQuery(s, &info, sizeof(info));	do {	    bottom = info.BaseAddress;	    VirtualQuery(bottom - 1, &info, sizeof(info));	} while ((info.Protect & PAGE_READWRITE)		 && !(info.Protect & PAGE_GUARD));	return(bottom);    }# endifvoid GC_push_all_stacks(){  DWORD thread_id = GetCurrentThreadId();  GC_bool found_me = FALSE;  int i;  int dummy;  ptr_t sp, stack_min;  GC_thread thread;  LONG my_max = GC_get_max_thread_index();    for (i = 0; i <= my_max; i++) {    thread = thread_table + i;    if (thread -> in_use && thread -> stack_base) {      if (thread -> id == thread_id) {	sp = (ptr_t) &dummy;	found_me = TRUE;      } else {        CONTEXT context;        context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;        if (!GetThreadContext(thread_table[i].handle, &context))	  ABORT("GetThreadContext failed");        /* Push all registers that might point into the heap.  Frame	*/        /* pointer registers are included in case client code was	*/        /* compiled with the 'omit frame pointer' optimisation.		*/#       define PUSH1(reg) GC_push_one((word)context.reg)#       define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)#       define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)#       if defined(I386)          PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);	  sp = (ptr_t)context.Esp;#       elif defined(ARM32)	  PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);	  sp = (ptr_t)context.Sp;#       elif defined(SHx)	  PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);	  PUSH2(R12,R13), PUSH1(R14);	  sp = (ptr_t)context.R15;#       elif defined(MIPS)	  PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);	  PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);	  PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);	  PUSH4(IntT9,IntK0,IntK1,IntS8);	  sp = (ptr_t)context.IntSp;#       elif defined(PPC)	  PUSH4(Gpr0, Gpr3, Gpr4, Gpr5),  PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);	  PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);	  PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);	  PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);	  sp = (ptr_t)context.Gpr1;#       elif defined(ALPHA)	  PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);	  PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);	  PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);	  PUSH4(IntT10,IntT11,IntT12,IntAt);	  sp = (ptr_t)context.IntSp;#       else#         error "architecture is not supported"#       endif      }      stack_min = GC_get_stack_min(thread->stack_base);      if (sp >= stack_min && sp < thread->stack_base)

⌨️ 快捷键说明

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