[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.3

version 1.1, 1999/12/03 07:39:10 version 1.3, 2001/04/20 07:39:20
Line 1 
Line 1 
 #ifdef WIN32_THREADS  #if defined(GC_WIN32_THREADS) || defined(WIN32_THREADS)
   
 #include "gc_priv.h"  #include "private/gc_priv.h"
   
   #if 0
 #define STRICT  #define STRICT
 #include <windows.h>  #include <windows.h>
   #endif
   
 #define MAX_THREADS 64  #define MAX_THREADS 64
   
Line 22  volatile GC_bool GC_please_stop = FALSE;
Line 24  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.                       */
   }
   
 void GC_stop_world()  void GC_stop_world()
 {  {
   DWORD thread_id = GetCurrentThreadId();    DWORD thread_id = GetCurrentThreadId();
Line 31  void GC_stop_world()
Line 40  void GC_stop_world()
   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;
               thread_table[i].in_use = FALSE;
               CloseHandle(thread_table[i].handle);
               BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
               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 80  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 92  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 125  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)            if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
             ABORT("Thread stack pointer out of range");                || 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.Ebx);            GC_push_one ((word) thread_table[i].context.Esi);
         GC_push_one ((word) thread_table[i].context.Edx);            GC_push_one ((word) thread_table[i].context.Ebp);
         GC_push_one ((word) thread_table[i].context.Ecx);            GC_push_one ((word) thread_table[i].context.Ebx);
         GC_push_one ((word) thread_table[i].context.Eax);            GC_push_one ((word) thread_table[i].context.Edx);
         GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack);            GC_push_one ((word) thread_table[i].context.Ecx);
             GC_push_one ((word) thread_table[i].context.Eax);
             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 331  void GC_get_next_stack(char *start, char **lo, char **
     if (*lo < start) *lo = start;      if (*lo < start) *lo = start;
 }  }
   
   
   # ifdef MSWINCE
   
   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.                  */
       __try {
           ret = args.start (args.param);
       } __finally {
           LOCK();
           args.entry->stack = 0;
           args.entry->in_use = FALSE;
                 /* cast away volatile qualifier */
           BZERO((void *) &args.entry->context, sizeof(CONTEXT));
           UNLOCK();
       }
   
       return ret;
   }
   
   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);
   
 /*  /*
Line 151  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
Line 529  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
       /* The following should be a noop according to the win32  */        /* The following should be a noop according to the win32  */
       /* documentation.  There is empirical evidence that it    */        /* documentation.  There is empirical evidence that it    */
       /* isn't.         - HB                                    */        /* isn't.         - HB                                    */
 #     ifndef SMALL_CONFIG  #     ifdef MPROTECT_VDB
        if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);         if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
 #     endif  #     endif
   
       for (i = 0; InterlockedExchange(&thread_table[i].in_use,1) != 0; i++) {        for (i = 0;
                                  /* cast away volatile qualifier */
              InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
              i++) {
         /* Compare-and-swap would make this cleaner, but that's not     */          /* Compare-and-swap would make this cleaner, but that's not     */
         /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */          /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */
         /* InterlockedExchange is supposed to be replaced by            */          /* InterlockedExchange is supposed to be replaced by            */
Line 166  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
Line 547  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
       }        }
       thread_table[i].id = GetCurrentThreadId();        thread_table[i].id = GetCurrentThreadId();
       if (!DuplicateHandle(GetCurrentProcess(),        if (!DuplicateHandle(GetCurrentProcess(),
                            GetCurrentThread(),                             GetCurrentThread(),
                            GetCurrentProcess(),                             GetCurrentProcess(),
                            &thread_table[i].handle,                             /* cast away volatile qualifier */
                              (HANDLE *) &thread_table[i].handle,
                            0,                             0,
                            0,                             0,
                            DUPLICATE_SAME_ACCESS)) {                             DUPLICATE_SAME_ACCESS)) {
             DWORD last_error = GetLastError();          DWORD last_error = GetLastError();
             GC_printf1("Last error code: %lx\n", last_error);          GC_printf1("Last error code: %lx\n", last_error);
             ABORT("DuplicateHandle failed");          ABORT("DuplicateHandle failed");
       }        }
       thread_table[i].stack = GC_get_stack_base();        thread_table[i].stack = GC_get_stack_base();
       /* If this thread is being created while we are trying to stop    */        /* If this thread is being created while we are trying to stop    */
Line 183  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
Line 565  BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVO
       while (GC_please_stop) Sleep(20);        while (GC_please_stop) Sleep(20);
     }      }
     break;      break;
   case DLL_PROCESS_DETACH:  
   case DLL_THREAD_DETACH:    case DLL_THREAD_DETACH:
     {      {
       int i;        int i;
       DWORD thread_id = GetCurrentThreadId();        DWORD thread_id = GetCurrentThreadId();
       LOCK();        LOCK();
       for (i = 0;        for (i = 0;
            thread_table[i].stack == 0 || thread_table[i].id != thread_id;             i < MAX_THREADS &&
            i++) {             (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
         if (i == MAX_THREADS - 1)             i++) {}
           ABORT("thread not found on detach");        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));
       }        }
       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();
     }      }
     break;      break;
     case DLL_PROCESS_DETACH:
       {
         int i;
   
         LOCK();
         for (i = 0; i < MAX_THREADS; ++i)
         {
             if (thread_table[i].in_use)
             {
                 thread_table[i].stack = 0;
                 thread_table[i].in_use = FALSE;
                 CloseHandle(thread_table[i].handle);
                 BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
             }
         }
         UNLOCK();
   
         GC_deinit();
         DeleteCriticalSection(&GC_allocate_ml);
       }
       break;
   
   }    }
   return TRUE;    return TRUE;
 }  }
   
   # endif /* !MSWINCE */
   
 #endif /* WIN32_THREADS */  #endif /* WIN32_THREADS */

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

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