[BACK]Return to win32_threads.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Diff for /OpenXM_contrib2/asir2000/gc/win32_threads.c between version 1.1 and 1.6

version 1.1, 1999/12/03 07:39:10 version 1.6, 2003/06/24 05:11:34
Line 1 
Line 1 
 #ifdef WIN32_THREADS  #if defined(GC_WIN32_THREADS)
   
 #include "gc_priv.h"  #include "private/gc_priv.h"
   
 #define STRICT  
 #include <windows.h>  #include <windows.h>
   
 #define MAX_THREADS 64  #ifdef CYGWIN32
   # include <errno.h>
   
    /* Cygwin-specific forward decls */
   # undef pthread_create
   # undef pthread_sigmask
   # undef pthread_join
   # undef dlopen
   
   # define DEBUG_CYGWIN_THREADS 0
   
     GC_bool GC_thr_initialized = FALSE;
     void * GC_start_routine(void * arg);
     void GC_thread_exit_proc(void *arg);
   
   #endif
   
   #ifndef MAX_THREADS
   # define MAX_THREADS 64
   #endif
   
 struct thread_entry {  struct thread_entry {
   LONG in_use;    LONG in_use;
   DWORD id;    DWORD id;
Line 16  struct thread_entry {
Line 33  struct thread_entry {
                         /* !in_use ==> stack == 0       */                          /* !in_use ==> stack == 0       */
   CONTEXT context;    CONTEXT context;
   GC_bool suspended;    GC_bool suspended;
   
   # ifdef CYGWIN32
       void *status; /* hold exit value until join in case it's a pointer */
       pthread_t pthread_id;
   # endif
   
 };  };
   
 volatile GC_bool GC_please_stop = FALSE;  volatile GC_bool GC_please_stop = FALSE;
   
 volatile struct thread_entry thread_table[MAX_THREADS];  volatile struct thread_entry thread_table[MAX_THREADS];
   
   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 */
       for (i = 0; i < MAX_THREADS; i++)
         if (thread_table[i].in_use) GC_push_all((ptr_t)&(thread_table[i].status),(ptr_t)(&(thread_table[i].status)+1));
     }
   # endif
   }
   
 void GC_stop_world()  void GC_stop_world()
 {  {
   DWORD thread_id = GetCurrentThreadId();    DWORD thread_id = GetCurrentThreadId();
   int i;    int i;
   
   #ifdef CYGWIN32
     if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
   #endif
   
   GC_please_stop = TRUE;    GC_please_stop = TRUE;
   for (i = 0; i < MAX_THREADS; i++)    for (i = 0; i < MAX_THREADS; i++)
     if (thread_table[i].stack != 0      if (thread_table[i].stack != 0
         && thread_table[i].id != thread_id) {          && thread_table[i].id != thread_id) {
       if (SuspendThread(thread_table[i].handle) == (DWORD)-1)  #     ifdef MSWINCE
         ABORT("SuspendThread failed");          /* 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 = 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);
               BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
   #         endif
             continue;
           }
           if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
             ABORT("SuspendThread failed");
   #     endif
       thread_table[i].suspended = TRUE;        thread_table[i].suspended = TRUE;
     }      }
 }  }
Line 51  void GC_start_world()
Line 115  void GC_start_world()
   GC_please_stop = FALSE;    GC_please_stop = FALSE;
 }  }
   
   # ifdef _MSC_VER
   #   pragma warning(disable:4715)
   # endif
 ptr_t GC_current_stackbottom()  ptr_t GC_current_stackbottom()
 {  {
   DWORD thread_id = GetCurrentThreadId();    DWORD thread_id = GetCurrentThreadId();
Line 60  ptr_t GC_current_stackbottom()
Line 127  ptr_t GC_current_stackbottom()
       return thread_table[i].stack;        return thread_table[i].stack;
   ABORT("no thread table entry for current thread");    ABORT("no thread table entry for current thread");
 }  }
   # ifdef _MSC_VER
   #   pragma warning(default:4715)
   # endif
   
 ptr_t GC_get_lo_stack_addr(ptr_t s)  # ifdef MSWINCE
 {      /* The VirtualQuery calls below won't work properly on WinCE, but   */
     ptr_t bottom;      /* since each stack is restricted to an aligned 64K region of       */
     MEMORY_BASIC_INFORMATION info;      /* virtual memory we can just take the next lowest multiple of 64K. */
     VirtualQuery(s, &info, sizeof(info));  #   define GC_get_lo_stack_addr(s) \
     do {          ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
         bottom = info.BaseAddress;  # else
         VirtualQuery(bottom - 1, &info, sizeof(info));      static ptr_t GC_get_lo_stack_addr(ptr_t s)
     } while ((info.Protect & PAGE_READWRITE) && !(info.Protect & PAGE_GUARD));      {
     return(bottom);          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);
       }
   # endif
   
 void GC_push_all_stacks()  void GC_push_all_stacks()
 {  {
Line 81  void GC_push_all_stacks()
Line 160  void GC_push_all_stacks()
     if (thread_table[i].stack) {      if (thread_table[i].stack) {
       ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);        ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);
       if (thread_table[i].id == thread_id)        if (thread_table[i].id == thread_id)
         GC_push_all(&i, thread_table[i].stack);          GC_push_all_stack((ptr_t)&i, thread_table[i].stack);
       else {        else {
         thread_table[i].context.ContextFlags          thread_table[i].context.ContextFlags
                         = (CONTEXT_INTEGER|CONTEXT_CONTROL);                          = (CONTEXT_INTEGER|CONTEXT_CONTROL);
         if (!GetThreadContext(thread_table[i].handle,          if (!GetThreadContext(thread_table[i].handle,
                               &thread_table[i].context))                                  /* cast away volatile qualifier */
                                   (LPCONTEXT)&thread_table[i].context))
           ABORT("GetThreadContext failed");            ABORT("GetThreadContext failed");
         if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack  #       ifdef I386
             || thread_table[i].context.Esp < (DWORD)bottom)            GC_push_one ((word) thread_table[i].context.Edi);
             ABORT("Thread stack pointer out of range");            GC_push_one ((word) thread_table[i].context.Esi);
         GC_push_one ((word) thread_table[i].context.Edi);            GC_push_one ((word) thread_table[i].context.Ebp);
         GC_push_one ((word) thread_table[i].context.Esi);            GC_push_one ((word) thread_table[i].context.Ebx);
         GC_push_one ((word) thread_table[i].context.Ebx);            GC_push_one ((word) thread_table[i].context.Edx);
         GC_push_one ((word) thread_table[i].context.Edx);            GC_push_one ((word) thread_table[i].context.Ecx);
         GC_push_one ((word) thread_table[i].context.Ecx);            GC_push_one ((word) thread_table[i].context.Eax);
         GC_push_one ((word) thread_table[i].context.Eax);            if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
         GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack);                || thread_table[i].context.Esp < (DWORD)bottom) {
                 WARN("Thread stack pointer 0x%lx out of range, pushing everything",
                      thread_table[i].context.Esp);
                 GC_push_all_stack((char *) bottom, thread_table[i].stack);
             } else {
                 GC_push_all_stack((char *) thread_table[i].context.Esp,
                                   thread_table[i].stack);
             }
   #       else
   #       ifdef ARM32
             if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack
                 || thread_table[i].context.Sp < (DWORD)bottom)
                 ABORT("Thread stack pointer out of range");
             GC_push_one ((word) thread_table[i].context.R0);
             GC_push_one ((word) thread_table[i].context.R1);
             GC_push_one ((word) thread_table[i].context.R2);
             GC_push_one ((word) thread_table[i].context.R3);
             GC_push_one ((word) thread_table[i].context.R4);
             GC_push_one ((word) thread_table[i].context.R5);
             GC_push_one ((word) thread_table[i].context.R6);
             GC_push_one ((word) thread_table[i].context.R7);
             GC_push_one ((word) thread_table[i].context.R8);
             GC_push_one ((word) thread_table[i].context.R9);
             GC_push_one ((word) thread_table[i].context.R10);
             GC_push_one ((word) thread_table[i].context.R11);
             GC_push_one ((word) thread_table[i].context.R12);
             GC_push_all_stack((char *) thread_table[i].context.Sp,
                               thread_table[i].stack);
   #       else
   #       ifdef SHx
             if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack
                 || thread_table[i].context.R15 < (DWORD)bottom)
                 ABORT("Thread stack pointer out of range");
             GC_push_one ((word) thread_table[i].context.R0);
             GC_push_one ((word) thread_table[i].context.R1);
             GC_push_one ((word) thread_table[i].context.R2);
             GC_push_one ((word) thread_table[i].context.R3);
             GC_push_one ((word) thread_table[i].context.R4);
             GC_push_one ((word) thread_table[i].context.R5);
             GC_push_one ((word) thread_table[i].context.R6);
             GC_push_one ((word) thread_table[i].context.R7);
             GC_push_one ((word) thread_table[i].context.R8);
             GC_push_one ((word) thread_table[i].context.R9);
             GC_push_one ((word) thread_table[i].context.R10);
             GC_push_one ((word) thread_table[i].context.R11);
             GC_push_one ((word) thread_table[i].context.R12);
             GC_push_one ((word) thread_table[i].context.R13);
             GC_push_one ((word) thread_table[i].context.R14);
             GC_push_all_stack((char *) thread_table[i].context.R15,
                               thread_table[i].stack);
   #       else
   #       ifdef MIPS
             if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
                 || thread_table[i].context.IntSp < (DWORD)bottom)
                 ABORT("Thread stack pointer out of range");
             GC_push_one ((word) thread_table[i].context.IntAt);
             GC_push_one ((word) thread_table[i].context.IntV0);
             GC_push_one ((word) thread_table[i].context.IntV1);
             GC_push_one ((word) thread_table[i].context.IntA0);
             GC_push_one ((word) thread_table[i].context.IntA1);
             GC_push_one ((word) thread_table[i].context.IntA2);
             GC_push_one ((word) thread_table[i].context.IntA3);
             GC_push_one ((word) thread_table[i].context.IntT0);
             GC_push_one ((word) thread_table[i].context.IntT1);
             GC_push_one ((word) thread_table[i].context.IntT2);
             GC_push_one ((word) thread_table[i].context.IntT3);
             GC_push_one ((word) thread_table[i].context.IntT4);
             GC_push_one ((word) thread_table[i].context.IntT5);
             GC_push_one ((word) thread_table[i].context.IntT6);
             GC_push_one ((word) thread_table[i].context.IntT7);
             GC_push_one ((word) thread_table[i].context.IntS0);
             GC_push_one ((word) thread_table[i].context.IntS1);
             GC_push_one ((word) thread_table[i].context.IntS2);
             GC_push_one ((word) thread_table[i].context.IntS3);
             GC_push_one ((word) thread_table[i].context.IntS4);
             GC_push_one ((word) thread_table[i].context.IntS5);
             GC_push_one ((word) thread_table[i].context.IntS6);
             GC_push_one ((word) thread_table[i].context.IntS7);
             GC_push_one ((word) thread_table[i].context.IntT8);
             GC_push_one ((word) thread_table[i].context.IntT9);
             GC_push_one ((word) thread_table[i].context.IntK0);
             GC_push_one ((word) thread_table[i].context.IntK1);
             GC_push_one ((word) thread_table[i].context.IntS8);
             GC_push_all_stack((char *) thread_table[i].context.IntSp,
                               thread_table[i].stack);
   #       else
   #       ifdef PPC
             if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack
                 || thread_table[i].context.Gpr1 < (DWORD)bottom)
                 ABORT("Thread stack pointer out of range");
             GC_push_one ((word) thread_table[i].context.Gpr0);
             /* Gpr1 is stack pointer */
             /* Gpr2 is global pointer */
             GC_push_one ((word) thread_table[i].context.Gpr3);
             GC_push_one ((word) thread_table[i].context.Gpr4);
             GC_push_one ((word) thread_table[i].context.Gpr5);
             GC_push_one ((word) thread_table[i].context.Gpr6);
             GC_push_one ((word) thread_table[i].context.Gpr7);
             GC_push_one ((word) thread_table[i].context.Gpr8);
             GC_push_one ((word) thread_table[i].context.Gpr9);
             GC_push_one ((word) thread_table[i].context.Gpr10);
             GC_push_one ((word) thread_table[i].context.Gpr11);
             GC_push_one ((word) thread_table[i].context.Gpr12);
             /* Gpr13 is reserved for the kernel */
             GC_push_one ((word) thread_table[i].context.Gpr14);
             GC_push_one ((word) thread_table[i].context.Gpr15);
             GC_push_one ((word) thread_table[i].context.Gpr16);
             GC_push_one ((word) thread_table[i].context.Gpr17);
             GC_push_one ((word) thread_table[i].context.Gpr18);
             GC_push_one ((word) thread_table[i].context.Gpr19);
             GC_push_one ((word) thread_table[i].context.Gpr20);
             GC_push_one ((word) thread_table[i].context.Gpr21);
             GC_push_one ((word) thread_table[i].context.Gpr22);
             GC_push_one ((word) thread_table[i].context.Gpr23);
             GC_push_one ((word) thread_table[i].context.Gpr24);
             GC_push_one ((word) thread_table[i].context.Gpr25);
             GC_push_one ((word) thread_table[i].context.Gpr26);
             GC_push_one ((word) thread_table[i].context.Gpr27);
             GC_push_one ((word) thread_table[i].context.Gpr28);
             GC_push_one ((word) thread_table[i].context.Gpr29);
             GC_push_one ((word) thread_table[i].context.Gpr30);
             GC_push_one ((word) thread_table[i].context.Gpr31);
             GC_push_all_stack((char *) thread_table[i].context.Gpr1,
                               thread_table[i].stack);
   #       else
   #       ifdef ALPHA
             if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
                 || thread_table[i].context.IntSp < (DWORD)bottom)
                 ABORT("Thread stack pointer out of range");
             GC_push_one ((word) thread_table[i].context.IntV0);
             GC_push_one ((word) thread_table[i].context.IntT0);
             GC_push_one ((word) thread_table[i].context.IntT1);
             GC_push_one ((word) thread_table[i].context.IntT2);
             GC_push_one ((word) thread_table[i].context.IntT3);
             GC_push_one ((word) thread_table[i].context.IntT4);
             GC_push_one ((word) thread_table[i].context.IntT5);
             GC_push_one ((word) thread_table[i].context.IntT6);
             GC_push_one ((word) thread_table[i].context.IntT7);
             GC_push_one ((word) thread_table[i].context.IntS0);
             GC_push_one ((word) thread_table[i].context.IntS1);
             GC_push_one ((word) thread_table[i].context.IntS2);
             GC_push_one ((word) thread_table[i].context.IntS3);
             GC_push_one ((word) thread_table[i].context.IntS4);
             GC_push_one ((word) thread_table[i].context.IntS5);
             GC_push_one ((word) thread_table[i].context.IntFp);
             GC_push_one ((word) thread_table[i].context.IntA0);
             GC_push_one ((word) thread_table[i].context.IntA1);
             GC_push_one ((word) thread_table[i].context.IntA2);
             GC_push_one ((word) thread_table[i].context.IntA3);
             GC_push_one ((word) thread_table[i].context.IntA4);
             GC_push_one ((word) thread_table[i].context.IntA5);
             GC_push_one ((word) thread_table[i].context.IntT8);
             GC_push_one ((word) thread_table[i].context.IntT9);
             GC_push_one ((word) thread_table[i].context.IntT10);
             GC_push_one ((word) thread_table[i].context.IntT11);
             GC_push_one ((word) thread_table[i].context.IntT12);
             GC_push_one ((word) thread_table[i].context.IntAt);
             GC_push_all_stack((char *) thread_table[i].context.IntSp,
                               thread_table[i].stack);
   #       else
                 --> architecture not supported
   #       endif /* !ALPHA */
   #       endif /* !PPC */
   #       endif /* !MIPS */
   #       endif /* !SHx */
   #       endif /* !ARM32 */
   #       endif /* !I386 */
       }        }
     }      }
 }  }
Line 124  void GC_get_next_stack(char *start, char **lo, char **
Line 370  void GC_get_next_stack(char *start, char **lo, char **
     if (*lo < start) *lo = start;      if (*lo < start) *lo = start;
 }  }
   
   #if !defined(CYGWIN32)
   
   #if !defined(MSWINCE) && defined(GC_DLL)
   
   /* We register threads from DllMain */
   
   GC_API HANDLE GC_CreateThread(
       LPSECURITY_ATTRIBUTES lpThreadAttributes,
       DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
       LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
   {
       return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
                           lpParameter, dwCreationFlags, lpThreadId);
   }
   
   #else /* defined(MSWINCE) || !defined(GC_DLL))  */
   
   /* We have no DllMain to take care of new threads.  Thus we     */
   /* must properly intercept thread creation.                     */
   
   typedef struct {
       HANDLE child_ready_h, parent_ready_h;
       volatile struct thread_entry * entry;
       LPTHREAD_START_ROUTINE start;
       LPVOID param;
   } thread_args;
   
   DWORD WINAPI thread_start(LPVOID arg);
   
   HANDLE WINAPI GC_CreateThread(
       LPSECURITY_ATTRIBUTES lpThreadAttributes,
       DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
       LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
   {
       HANDLE thread_h = NULL;
       HANDLE child_ready_h, parent_ready_h;
   
       int i;
       thread_args args;
   
       /* allocate thread slot */
       LOCK();
       for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
           ;
       if (i != MAX_THREADS) {
           thread_table[i].in_use = TRUE;
       }
       UNLOCK();
   
       if (i != MAX_THREADS) {
   
           /* create unnamed unsignalled events */
           if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
               if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
   
                   /* set up thread arguments */
                   args.child_ready_h = child_ready_h;
                   args.parent_ready_h = parent_ready_h;
                   args.entry = &thread_table[i];
                   args.start = lpStartAddress;
                   args.param = lpParameter;
   
                   thread_h = CreateThread(lpThreadAttributes,
                                           dwStackSize, thread_start,
                                           &args,
                                           dwCreationFlags & ~CREATE_SUSPENDED,
                                           lpThreadId);
   
                   if (thread_h) {
   
                       /* fill in ID and handle; tell child this is done */
                       thread_table[i].id = *lpThreadId;
                       thread_table[i].handle = thread_h;
                       SetEvent (parent_ready_h);
   
                       /* wait for child to fill in stack and copy args */
                       WaitForSingleObject (child_ready_h, INFINITE);
   
                       /* suspend the child if requested */
                       if (dwCreationFlags & CREATE_SUSPENDED)
                           SuspendThread (thread_h);
   
                       /* let child call given function now (or when resumed) */
                       SetEvent (parent_ready_h);
   
                   } else {
                       CloseHandle (parent_ready_h);
                   }
               }
           }
   
           CloseHandle (child_ready_h);
   
           if (thread_h == NULL)
               thread_table[i].in_use = FALSE;
   
       } else { /* no thread slot found */
           SetLastError (ERROR_TOO_MANY_TCBS);
       }
   
       return thread_h;
   }
   
   static DWORD WINAPI thread_start(LPVOID arg)
   {
       DWORD ret = 0;
       thread_args args = *(thread_args *)arg;
   
       /* wait for parent to fill in ID and handle */
       WaitForSingleObject (args.parent_ready_h, INFINITE);
       ResetEvent (args.parent_ready_h);
   
       /* fill in stack; tell parent this is done */
       args.entry->stack = GC_get_stack_base();
       SetEvent (args.child_ready_h);
   
       /* wait for parent to tell us to go (in case it needs to suspend us) */
       WaitForSingleObject (args.parent_ready_h, INFINITE);
       CloseHandle (args.parent_ready_h);
   
       /* Clear the thread entry even if we exit with an exception.        */
       /* This is probably pointless, since an uncaught exception is       */
       /* supposed to result in the process being killed.                  */
   #ifndef __GNUC__
       __try {
   #endif /* __GNUC__ */
           ret = args.start (args.param);
   #ifndef __GNUC__
       } __finally {
   #endif /* __GNUC__ */
           LOCK();
           args.entry->stack = 0;
           args.entry->in_use = FALSE;
                 /* cast away volatile qualifier */
           BZERO((void *) &args.entry->context, sizeof(CONTEXT));
           UNLOCK();
   #ifndef __GNUC__
       }
   #endif /* __GNUC__ */
   
       return ret;
   }
   #endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))  */
   
   #endif /* !CYGWIN32 */
   
   #ifdef MSWINCE
   
   typedef struct {
       HINSTANCE hInstance;
       HINSTANCE hPrevInstance;
       LPWSTR lpCmdLine;
       int nShowCmd;
   } main_thread_args;
   
   DWORD WINAPI main_thread_start(LPVOID arg);
   
   int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                      LPWSTR lpCmdLine, int nShowCmd)
   {
       DWORD exit_code = 1;
   
       main_thread_args args = {
           hInstance, hPrevInstance, lpCmdLine, nShowCmd
       };
       HANDLE thread_h;
       DWORD thread_id;
   
       /* initialize everything */
       InitializeCriticalSection(&GC_allocate_ml);
       GC_init();
   
       /* start the main thread */
       thread_h = GC_CreateThread(
           NULL, 0, main_thread_start, &args, 0, &thread_id);
   
       if (thread_h != NULL)
       {
           WaitForSingleObject (thread_h, INFINITE);
           GetExitCodeThread (thread_h, &exit_code);
           CloseHandle (thread_h);
       }
   
       GC_deinit();
       DeleteCriticalSection(&GC_allocate_ml);
   
       return (int) exit_code;
   }
   
   DWORD WINAPI main_thread_start(LPVOID arg)
   {
       main_thread_args * args = (main_thread_args *) arg;
   
       return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
                                  args->lpCmdLine, args->nShowCmd);
   }
   
   # else /* !MSWINCE */
   
 LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);  LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
   
   /* threadAttach/threadDetach routines used by both CYGWIN and DLL
    * implementation, since both recieve explicit notification on thread
    * creation/destruction.
    */
   static void threadAttach() {
     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 */
     /* inititalization 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((LONG*)&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");
     }
     thread_table[i].id = GetCurrentThreadId();
   # 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 = GC_get_stack_base();
     if (thread_table[i].stack == NULL)
       ABORT("Failed to find stack base in threadAttach");
     /* 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);
   }
   
   static void threadDetach(DWORD thread_id) {
     int i;
   
     LOCK();
     for (i = 0;
          i < MAX_THREADS &&
          !thread_table[i].in_use || thread_table[i].id != thread_id;
          i++) {}
     if (i >= MAX_THREADS ) {
       WARN("thread %ld not found on detach", (GC_word)thread_id);
     }
     else {
       thread_table[i].stack = 0;
       thread_table[i].in_use = FALSE;
       CloseHandle(thread_table[i].handle);
         /* cast away volatile qualifier */
       BZERO((void *)&thread_table[i].context, sizeof(CONTEXT));
     }
     UNLOCK();
   }
   
   #ifdef CYGWIN32
   
   /* Called by GC_init() - we hold the allocation lock.   */
   void GC_thr_init() {
       if (GC_thr_initialized) return;
       GC_thr_initialized = TRUE;
   
   #if 0
       /* this might already be handled in GC_init... */
       InitializeCriticalSection(&GC_allocate_ml);
   #endif
   
       /* Add the initial thread, so we can stop it.       */
       threadAttach();
   }
   
   struct start_info {
       void *(*start_routine)(void *);
       void *arg;
   };
   
   int GC_pthread_join(pthread_t pthread_id, void **retval) {
       int result;
       int i;
   
   #   if DEBUG_CYGWIN_THREADS
         GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",(int)pthread_self(),
                    GetCurrentThreadId(), (int)pthread_id);
   #   endif
   
       /* Can't do any table lookups here, because thread being joined
          might not have registered itself yet */
   
       result = pthread_join(pthread_id, retval);
   
       LOCK();
       for (i = 0; !thread_table[i].in_use || thread_table[i].pthread_id != pthread_id;
            i++) {
         if (i == MAX_THREADS - 1) {
           GC_printf1("Failed to find thread 0x%x in pthread_join()\n", pthread_id);
           ABORT("thread not found on detach");
         }
       }
       UNLOCK();
       threadDetach(thread_table[i].id);
   
   #   if DEBUG_CYGWIN_THREADS
         GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
                    (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
   #   endif
   
       return result;
   }
   
   /* 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 (!GC_is_initialized) GC_init();
                   /* make sure GC is initialized (i.e. main thread is attached) */
   
       /* 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 DEBUG_CYGWIN_THREADS
         GC_printf2("About to create a thread from 0x%x(0x%x)\n",(int)pthread_self(),
                                                                 GetCurrentThreadId);
   #   endif
       result = pthread_create(new_thread, attr, GC_start_routine, si);
   
       if (result) { /* failure */
           GC_free(si);
       }
   
       return(result);
   }
   
   void * GC_start_routine(void * arg)
   {
       struct start_info * si = arg;
       void * result;
       void *(*start)(void *);
       void *start_arg;
       pthread_t pthread_id;
       int i;
   
   #   if DEBUG_CYGWIN_THREADS
         GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
                                                      GetCurrentThreadId());
   #   endif
   
       /* If a GC occurs before the thread is registered, that GC will     */
       /* ignore this thread.  That's fine, since it will block trying to  */
       /* acquire the allocation lock, and won't yet hold interesting      */
       /* pointers.                                                        */
       LOCK();
       /* We register the thread here instead of in the parent, so that    */
       /* we don't need to hold the allocation lock during pthread_create. */
       threadAttach();
       UNLOCK();
   
       start = si -> start_routine;
       start_arg = si -> arg;
       pthread_id = pthread_self();
   
       GC_free(si); /* was allocated uncollectable */
   
       pthread_cleanup_push(GC_thread_exit_proc, pthread_id);
       result = (*start)(start_arg);
       pthread_cleanup_pop(0);
   
   #   if DEBUG_CYGWIN_THREADS
         GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
                    (int)pthread_self(),GetCurrentThreadId());
   #   endif
   
       LOCK();
       for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
         if (i == MAX_THREADS - 1)
           ABORT("thread not found on exit");
       }
       thread_table[i].status = result;
       UNLOCK();
   
       return(result);
   }
   
   void GC_thread_exit_proc(void *arg)
   {
       pthread_t pthread_id = (pthread_t)arg;
       int i;
   
   #   if DEBUG_CYGWIN_THREADS
         GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
                    (int)pthread_self(),GetCurrentThreadId());
   #   endif
   
       LOCK();
       for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
         if (i == MAX_THREADS - 1)
           ABORT("thread not found on exit");
       }
       UNLOCK();
   
   #if 0
       /* TODO: we need a way to get the exit value after a pthread_exit so we can stash it safely away */
       thread_table[i].status = ???
   #endif
   }
   
   /* nothing required here... */
   int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
     return pthread_sigmask(how, set, oset);
   }
   int GC_pthread_detach(pthread_t thread) {
     return pthread_detach(thread);
   }
   #else /* !CYGWIN32 */
   
 /*  /*
  * This isn't generally safe, since DllMain is not premptible.   * We avoid acquiring locks here, since this doesn't seem to be preemptable.
  * If another thread holds the lock while this runs we're in trouble.  
  * Pontus Rydin suggests wrapping the thread start routine instead.   * Pontus Rydin suggests wrapping the thread start routine instead.
  */   */
   #ifdef GC_DLL
 BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
 {  {
   switch (reason) {    switch (reason) {
Line 139  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
Line 829  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
     GC_init();  /* Force initialization before thread attach.   */      GC_init();  /* Force initialization before thread attach.   */
     /* fall through */      /* fall through */
   case DLL_THREAD_ATTACH:    case DLL_THREAD_ATTACH:
     {      threadAttach();
       int i;      break;
       /* 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     */  
       /* inititalization tasks".)                                       */  
       /* Hence we make do with nonblocking synchronization.             */  
   
       /* The following should be a noop according to the win32  */    case DLL_THREAD_DETACH:
       /* documentation.  There is empirical evidence that it    */      threadDetach(GetCurrentThreadId());
       /* isn't.         - HB                                    */  
 #     ifndef SMALL_CONFIG  
        if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);  
 #     endif  
   
       for (i = 0; InterlockedExchange(&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");  
       }  
       thread_table[i].id = GetCurrentThreadId();  
       if (!DuplicateHandle(GetCurrentProcess(),  
                            GetCurrentThread(),  
                            GetCurrentProcess(),  
                            &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 = GC_get_stack_base();  
       /* 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);  
     }  
     break;      break;
   
   case DLL_PROCESS_DETACH:    case DLL_PROCESS_DETACH:
   case DLL_THREAD_DETACH:  
     {      {
       int i;        int i;
       DWORD thread_id = GetCurrentThreadId();  
       LOCK();        LOCK();
       for (i = 0;        for (i = 0; i < MAX_THREADS; ++i)
            thread_table[i].stack == 0 || thread_table[i].id != thread_id;        {
            i++) {            if (thread_table[i].in_use)
         if (i == MAX_THREADS - 1)            {
           ABORT("thread not found on detach");                thread_table[i].stack = 0;
                 thread_table[i].in_use = FALSE;
                 CloseHandle(thread_table[i].handle);
                 BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
             }
       }        }
       thread_table[i].stack = 0;  
       thread_table[i].in_use = FALSE;  
       CloseHandle(thread_table[i].handle);  
       BZERO(&thread_table[i].context, sizeof(CONTEXT));  
       UNLOCK();        UNLOCK();
   
         GC_deinit();
         DeleteCriticalSection(&GC_allocate_ml);
     }      }
     break;      break;
   
   }    }
   return TRUE;    return TRUE;
 }  }
   #endif /* GC_DLL */
   #endif /* !CYGWIN32 */
   
 #endif /* WIN32_THREADS */  # endif /* !MSWINCE */
   
   #endif /* GC_WIN32_THREADS */

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.6

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>