~ubuntu-branches/ubuntu/hardy/libgc/hardy-updates

« back to all changes in this revision

Viewing changes to win32_threads.c

  • Committer: Bazaar Package Importer
  • Author(s): Ryan Murray
  • Date: 2005-02-03 00:50:53 UTC
  • mto: (3.1.1 etch) (1.2.4 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050203005053-9c0v9r2qcm2g1cfp
Tags: upstream-6.4
ImportĀ upstreamĀ versionĀ 6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#if defined(GC_WIN32_THREADS)
2
 
 
3
1
#include "private/gc_priv.h"
4
2
 
5
 
#if 0
6
 
#define STRICT
 
3
#if defined(GC_WIN32_THREADS) 
 
4
 
7
5
#include <windows.h>
8
 
#endif
9
 
 
10
 
#define MAX_THREADS 64
11
 
 
12
 
struct thread_entry {
13
 
  LONG in_use;
 
6
 
 
7
#ifdef CYGWIN32
 
8
# include <errno.h>
 
9
 
 
10
 /* Cygwin-specific forward decls */
 
11
# undef pthread_create 
 
12
# undef pthread_sigmask 
 
13
# undef pthread_join 
 
14
# undef dlopen 
 
15
 
 
16
# define DEBUG_CYGWIN_THREADS 0
 
17
 
 
18
  void * GC_start_routine(void * arg);
 
19
  void GC_thread_exit_proc(void *arg);
 
20
 
 
21
#endif
 
22
 
 
23
/* The type of the first argument to InterlockedExchange.       */
 
24
/* Documented to be LONG volatile *, but at least gcc likes     */
 
25
/* this better.                                                 */
 
26
typedef LONG * IE_t;
 
27
 
 
28
#ifndef MAX_THREADS
 
29
# define MAX_THREADS 256
 
30
    /* FIXME:                                                   */
 
31
    /* Things may get quite slow for large numbers of threads,  */
 
32
    /* since we look them up with sequential search.            */
 
33
#endif
 
34
 
 
35
GC_bool GC_thr_initialized = FALSE;
 
36
 
 
37
DWORD GC_main_thread = 0;
 
38
 
 
39
struct GC_thread_Rep {
 
40
  LONG in_use; /* Updated without lock. */
 
41
                        /* We assert that unused        */
 
42
                        /* entries have invalid ids of  */
 
43
                        /* zero and zero stack fields.  */
14
44
  DWORD id;
15
45
  HANDLE handle;
16
 
  void *stack;          /* The cold end of the stack.   */
 
46
  ptr_t stack_base;     /* The cold end of the stack.   */
17
47
                        /* 0 ==> entry not valid.       */
18
 
                        /* !in_use ==> stack == 0       */
19
 
  CONTEXT context;
 
48
                        /* !in_use ==> stack_base == 0  */
20
49
  GC_bool suspended;
 
50
 
 
51
# ifdef CYGWIN32
 
52
    void *status; /* hold exit value until join in case it's a pointer */
 
53
    pthread_t pthread_id;
 
54
    short flags;                /* Protected by GC lock.        */
 
55
#       define FINISHED 1       /* Thread has exited.   */
 
56
#       define DETACHED 2       /* Thread is intended to be detached.   */
 
57
# endif
21
58
};
22
59
 
 
60
typedef volatile struct GC_thread_Rep * GC_thread;
 
61
 
 
62
/*
 
63
 * We generally assume that volatile ==> memory ordering, at least among
 
64
 * volatiles.
 
65
 */
 
66
 
23
67
volatile GC_bool GC_please_stop = FALSE;
24
68
 
25
 
volatile struct thread_entry thread_table[MAX_THREADS];
 
69
volatile struct GC_thread_Rep thread_table[MAX_THREADS];
 
70
 
 
71
volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table */
 
72
                                       /* that was ever used.           */
 
73
 
 
74
extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
 
75
 
 
76
/*
 
77
 * This may be called from DllMain, and hence operates under unusual
 
78
 * constraints.
 
79
 */
 
80
static GC_thread GC_new_thread(void) {
 
81
  int i;
 
82
  /* It appears to be unsafe to acquire a lock here, since this */
 
83
  /* code is apparently not preeemptible on some systems.       */
 
84
  /* (This is based on complaints, not on Microsoft's official  */
 
85
  /* documentation, which says this should perform "only simple */
 
86
  /* initialization tasks".)                                    */
 
87
  /* Hence we make do with nonblocking synchronization.         */
 
88
 
 
89
  /* The following should be a noop according to the win32      */
 
90
  /* documentation.  There is empirical evidence that it        */
 
91
  /* isn't.             - HB                                    */
 
92
# if defined(MPROTECT_VDB)
 
93
   if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
 
94
# endif
 
95
                /* cast away volatile qualifier */
 
96
  for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) {
 
97
    /* Compare-and-swap would make this cleaner, but that's not         */
 
98
    /* supported before Windows 98 and NT 4.0.  In Windows 2000,        */
 
99
    /* InterlockedExchange is supposed to be replaced by                */
 
100
    /* InterlockedExchangePointer, but that's not really what I         */
 
101
    /* want here.                                                       */
 
102
    if (i == MAX_THREADS - 1)
 
103
      ABORT("too many threads");
 
104
  }
 
105
  /* Update GC_max_thread_index if necessary.  The following is safe,   */
 
106
  /* and unlike CompareExchange-based solutions seems to work on all    */
 
107
  /* Windows95 and later platforms.                                     */
 
108
  /* Unfortunately, GC_max_thread_index may be temporarily out of       */
 
109
  /* bounds, so readers have to compensate.                             */
 
110
  while (i > GC_max_thread_index) {
 
111
    InterlockedIncrement((IE_t)&GC_max_thread_index);
 
112
  }
 
113
  if (GC_max_thread_index >= MAX_THREADS) {
 
114
    /* We overshot due to simultaneous increments.      */
 
115
    /* Setting it to MAX_THREADS-1 is always safe.      */
 
116
    GC_max_thread_index = MAX_THREADS - 1;
 
117
  }
 
118
  
 
119
# ifdef CYGWIN32
 
120
    thread_table[i].pthread_id = pthread_self();
 
121
# endif
 
122
  if (!DuplicateHandle(GetCurrentProcess(),
 
123
                       GetCurrentThread(),
 
124
                       GetCurrentProcess(),
 
125
                       (HANDLE*)&thread_table[i].handle,
 
126
                       0,
 
127
                       0,
 
128
                       DUPLICATE_SAME_ACCESS)) {
 
129
        DWORD last_error = GetLastError();
 
130
        GC_printf1("Last error code: %lx\n", last_error);
 
131
        ABORT("DuplicateHandle failed");
 
132
  }
 
133
  thread_table[i].stack_base = GC_get_stack_base();
 
134
  /* Up until this point, GC_push_all_stacks considers this thread      */
 
135
  /* invalid.                                                           */
 
136
  if (thread_table[i].stack_base == NULL) 
 
137
    ABORT("Failed to find stack base in GC_new_thread");
 
138
  /* Up until this point, this entry is viewed as reserved but invalid  */
 
139
  /* by GC_delete_thread.                                               */
 
140
  thread_table[i].id = GetCurrentThreadId();
 
141
  /* If this thread is being created while we are trying to stop        */
 
142
  /* the world, wait here.  Hopefully this can't happen on any  */
 
143
  /* systems that don't allow us to block here.                 */
 
144
  while (GC_please_stop) Sleep(20);
 
145
  return thread_table + i;
 
146
}
 
147
 
 
148
/*
 
149
 * GC_max_thread_index may temporarily be larger than MAX_THREADS.
 
150
 * To avoid subscript errors, we check on access.
 
151
 */
 
152
#ifdef __GNUC__
 
153
__inline__
 
154
#endif
 
155
LONG GC_get_max_thread_index()
 
156
{
 
157
  LONG my_max = GC_max_thread_index;
 
158
 
 
159
  if (my_max >= MAX_THREADS) return MAX_THREADS-1;
 
160
  return my_max;
 
161
}
 
162
 
 
163
/* This is intended to be lock-free, though that                        */
 
164
/* assumes that the CloseHandle becomes visible before the              */
 
165
/* in_use assignment.                                                   */
 
166
static void GC_delete_gc_thread(GC_thread thr)
 
167
{
 
168
    CloseHandle(thr->handle);
 
169
      /* cast away volatile qualifier */
 
170
    thr->stack_base = 0;
 
171
    thr->id = 0;
 
172
#   ifdef CYGWIN32
 
173
      thr->pthread_id = 0;
 
174
#   endif /* CYGWIN32 */
 
175
    thr->in_use = FALSE;
 
176
}
 
177
 
 
178
static void GC_delete_thread(DWORD thread_id) {
 
179
  int i;
 
180
  LONG my_max = GC_get_max_thread_index();
 
181
 
 
182
  for (i = 0;
 
183
       i <= my_max &&
 
184
       (!thread_table[i].in_use || thread_table[i].id != thread_id);
 
185
       /* Must still be in_use, since nobody else can store our thread_id. */
 
186
       i++) {}
 
187
  if (i > my_max) {
 
188
    WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id);
 
189
  } else {
 
190
    GC_delete_gc_thread(thread_table+i);
 
191
  }
 
192
}
 
193
 
 
194
 
 
195
#ifdef CYGWIN32
 
196
 
 
197
/* Return a GC_thread corresponding to a given pthread_t.       */
 
198
/* Returns 0 if it's not there.                                 */
 
199
/* We assume that this is only called for pthread ids that      */
 
200
/* have not yet terminated or are still joinable.               */
 
201
static GC_thread GC_lookup_thread(pthread_t id)
 
202
{
 
203
  int i;
 
204
  LONG my_max = GC_get_max_thread_index();
 
205
 
 
206
  for (i = 0;
 
207
       i <= my_max &&
 
208
       (!thread_table[i].in_use || thread_table[i].pthread_id != id
 
209
        || !thread_table[i].in_use);
 
210
       /* Must still be in_use, since nobody else can store our thread_id. */
 
211
       i++);
 
212
  if (i > my_max) return 0;
 
213
  return thread_table + i;
 
214
}
 
215
 
 
216
#endif /* CYGWIN32 */
26
217
 
27
218
void GC_push_thread_structures GC_PROTO((void))
28
219
{
29
220
    /* Unlike the other threads implementations, the thread table here  */
30
221
    /* contains no pointers to the collectable heap.  Thus we have      */
31
222
    /* no private structures we need to preserve.                       */
 
223
# ifdef CYGWIN32
 
224
  { int i; /* pthreads may keep a pointer in the thread exit value */
 
225
    LONG my_max = GC_get_max_thread_index();
 
226
 
 
227
    for (i = 0; i <= my_max; i++)
 
228
      if (thread_table[i].in_use)
 
229
        GC_push_all((ptr_t)&(thread_table[i].status),
 
230
                    (ptr_t)(&(thread_table[i].status)+1));
 
231
  }
 
232
# endif
32
233
}
33
234
 
34
235
void GC_stop_world()
36
237
  DWORD thread_id = GetCurrentThreadId();
37
238
  int i;
38
239
 
 
240
  if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
 
241
 
39
242
  GC_please_stop = TRUE;
40
 
  for (i = 0; i < MAX_THREADS; i++)
41
 
    if (thread_table[i].stack != 0
 
243
  for (i = 0; i <= GC_get_max_thread_index(); i++)
 
244
    if (thread_table[i].stack_base != 0
42
245
        && thread_table[i].id != thread_id) {
43
246
#     ifdef MSWINCE
44
247
        /* SuspendThread will fail if thread is running kernel code */
53
256
        DWORD exitCode; 
54
257
        if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
55
258
            exitCode != STILL_ACTIVE) {
56
 
            thread_table[i].stack = 0;
 
259
          thread_table[i].stack_base = 0; /* prevent stack from being pushed */
 
260
#         ifndef CYGWIN32
 
261
            /* this breaks pthread_join on Cygwin, which is guaranteed to  */
 
262
            /* only see user pthreads                                      */
57
263
            thread_table[i].in_use = FALSE;
58
264
            CloseHandle(thread_table[i].handle);
59
 
            BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
60
 
            continue;
 
265
#         endif
 
266
          continue;
61
267
        }
62
268
        if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
63
269
          ABORT("SuspendThread failed");
70
276
{
71
277
  DWORD thread_id = GetCurrentThreadId();
72
278
  int i;
73
 
  for (i = 0; i < MAX_THREADS; i++)
74
 
    if (thread_table[i].stack != 0 && thread_table[i].suspended
 
279
  LONG my_max = GC_get_max_thread_index();
 
280
 
 
281
  for (i = 0; i <= my_max; i++)
 
282
    if (thread_table[i].stack_base != 0 && thread_table[i].suspended
75
283
        && thread_table[i].id != thread_id) {
76
284
      if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
77
285
        ABORT("ResumeThread failed");
87
295
{
88
296
  DWORD thread_id = GetCurrentThreadId();
89
297
  int i;
90
 
  for (i = 0; i < MAX_THREADS; i++)
91
 
    if (thread_table[i].stack && thread_table[i].id == thread_id)
92
 
      return thread_table[i].stack;
 
298
  LONG my_max = GC_get_max_thread_index();
 
299
 
 
300
  for (i = 0; i <= my_max; i++)
 
301
    if (thread_table[i].stack_base && thread_table[i].id == thread_id)
 
302
      return thread_table[i].stack_base;
93
303
  ABORT("no thread table entry for current thread");
94
304
}
95
305
# ifdef _MSC_VER
100
310
    /* The VirtualQuery calls below won't work properly on WinCE, but   */
101
311
    /* since each stack is restricted to an aligned 64K region of       */
102
312
    /* virtual memory we can just take the next lowest multiple of 64K. */
103
 
#   define GC_get_lo_stack_addr(s) \
 
313
#   define GC_get_stack_min(s) \
104
314
        ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
105
315
# else
106
 
    static ptr_t GC_get_lo_stack_addr(ptr_t s)
 
316
    static ptr_t GC_get_stack_min(ptr_t s)
107
317
    {
108
318
        ptr_t bottom;
109
319
        MEMORY_BASIC_INFORMATION info;
120
330
void GC_push_all_stacks()
121
331
{
122
332
  DWORD thread_id = GetCurrentThreadId();
 
333
  GC_bool found_me = FALSE;
123
334
  int i;
124
 
  for (i = 0; i < MAX_THREADS; i++)
125
 
    if (thread_table[i].stack) {
126
 
      ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);
127
 
      if (thread_table[i].id == thread_id)
128
 
        GC_push_all_stack((ptr_t)&i, thread_table[i].stack);
 
335
  int dummy;
 
336
  ptr_t sp, stack_min;
 
337
  GC_thread thread;
 
338
  LONG my_max = GC_get_max_thread_index();
 
339
  
 
340
  for (i = 0; i <= my_max; i++) {
 
341
    thread = thread_table + i;
 
342
    if (thread -> in_use && thread -> stack_base) {
 
343
      if (thread -> id == thread_id) {
 
344
        sp = (ptr_t) &dummy;
 
345
        found_me = TRUE;
 
346
      } else {
 
347
        CONTEXT context;
 
348
        context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
 
349
        if (!GetThreadContext(thread_table[i].handle, &context))
 
350
          ABORT("GetThreadContext failed");
 
351
 
 
352
        /* Push all registers that might point into the heap.  Frame    */
 
353
        /* pointer registers are included in case client code was       */
 
354
        /* compiled with the 'omit frame pointer' optimisation.         */
 
355
#       define PUSH1(reg) GC_push_one((word)context.reg)
 
356
#       define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
 
357
#       define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
 
358
#       if defined(I386)
 
359
          PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
 
360
          sp = (ptr_t)context.Esp;
 
361
#       elif defined(ARM32)
 
362
          PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
 
363
          sp = (ptr_t)context.Sp;
 
364
#       elif defined(SHx)
 
365
          PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
 
366
          PUSH2(R12,R13), PUSH1(R14);
 
367
          sp = (ptr_t)context.R15;
 
368
#       elif defined(MIPS)
 
369
          PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
 
370
          PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
 
371
          PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
 
372
          PUSH4(IntT9,IntK0,IntK1,IntS8);
 
373
          sp = (ptr_t)context.IntSp;
 
374
#       elif defined(PPC)
 
375
          PUSH4(Gpr0, Gpr3, Gpr4, Gpr5),  PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
 
376
          PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
 
377
          PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
 
378
          PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
 
379
          sp = (ptr_t)context.Gpr1;
 
380
#       elif defined(ALPHA)
 
381
          PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
 
382
          PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
 
383
          PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
 
384
          PUSH4(IntT10,IntT11,IntT12,IntAt);
 
385
          sp = (ptr_t)context.IntSp;
 
386
#       else
 
387
#         error "architecture is not supported"
 
388
#       endif
 
389
      }
 
390
 
 
391
      stack_min = GC_get_stack_min(thread->stack_base);
 
392
 
 
393
      if (sp >= stack_min && sp < thread->stack_base)
 
394
        GC_push_all_stack(sp, thread->stack_base);
129
395
      else {
130
 
        thread_table[i].context.ContextFlags
131
 
                        = (CONTEXT_INTEGER|CONTEXT_CONTROL);
132
 
        if (!GetThreadContext(thread_table[i].handle,
133
 
                                /* cast away volatile qualifier */
134
 
                                (LPCONTEXT)&thread_table[i].context))
135
 
          ABORT("GetThreadContext failed");
136
 
#       ifdef I386
137
 
          if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
138
 
              || thread_table[i].context.Esp < (DWORD)bottom)
139
 
              ABORT("Thread stack pointer out of range");
140
 
          GC_push_one ((word) thread_table[i].context.Edi);
141
 
          GC_push_one ((word) thread_table[i].context.Esi);
142
 
          GC_push_one ((word) thread_table[i].context.Ebp);
143
 
          GC_push_one ((word) thread_table[i].context.Ebx);
144
 
          GC_push_one ((word) thread_table[i].context.Edx);
145
 
          GC_push_one ((word) thread_table[i].context.Ecx);
146
 
          GC_push_one ((word) thread_table[i].context.Eax);
147
 
          GC_push_all_stack((char *) thread_table[i].context.Esp,
148
 
                            thread_table[i].stack);
149
 
#       else
150
 
#       ifdef ARM32
151
 
          if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack
152
 
              || thread_table[i].context.Sp < (DWORD)bottom)
153
 
              ABORT("Thread stack pointer out of range");
154
 
          GC_push_one ((word) thread_table[i].context.R0);
155
 
          GC_push_one ((word) thread_table[i].context.R1);
156
 
          GC_push_one ((word) thread_table[i].context.R2);
157
 
          GC_push_one ((word) thread_table[i].context.R3);
158
 
          GC_push_one ((word) thread_table[i].context.R4);
159
 
          GC_push_one ((word) thread_table[i].context.R5);
160
 
          GC_push_one ((word) thread_table[i].context.R6);
161
 
          GC_push_one ((word) thread_table[i].context.R7);
162
 
          GC_push_one ((word) thread_table[i].context.R8);
163
 
          GC_push_one ((word) thread_table[i].context.R9);
164
 
          GC_push_one ((word) thread_table[i].context.R10);
165
 
          GC_push_one ((word) thread_table[i].context.R11);
166
 
          GC_push_one ((word) thread_table[i].context.R12);
167
 
          GC_push_all_stack((char *) thread_table[i].context.Sp,
168
 
                            thread_table[i].stack);
169
 
#       else
170
 
#       ifdef SHx
171
 
          if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack
172
 
              || thread_table[i].context.R15 < (DWORD)bottom)
173
 
              ABORT("Thread stack pointer out of range");
174
 
          GC_push_one ((word) thread_table[i].context.R0);
175
 
          GC_push_one ((word) thread_table[i].context.R1);
176
 
          GC_push_one ((word) thread_table[i].context.R2);
177
 
          GC_push_one ((word) thread_table[i].context.R3);
178
 
          GC_push_one ((word) thread_table[i].context.R4);
179
 
          GC_push_one ((word) thread_table[i].context.R5);
180
 
          GC_push_one ((word) thread_table[i].context.R6);
181
 
          GC_push_one ((word) thread_table[i].context.R7);
182
 
          GC_push_one ((word) thread_table[i].context.R8);
183
 
          GC_push_one ((word) thread_table[i].context.R9);
184
 
          GC_push_one ((word) thread_table[i].context.R10);
185
 
          GC_push_one ((word) thread_table[i].context.R11);
186
 
          GC_push_one ((word) thread_table[i].context.R12);
187
 
          GC_push_one ((word) thread_table[i].context.R13);
188
 
          GC_push_one ((word) thread_table[i].context.R14);
189
 
          GC_push_all_stack((char *) thread_table[i].context.R15,
190
 
                            thread_table[i].stack);
191
 
#       else
192
 
#       ifdef MIPS
193
 
          if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
194
 
              || thread_table[i].context.IntSp < (DWORD)bottom)
195
 
              ABORT("Thread stack pointer out of range");
196
 
          GC_push_one ((word) thread_table[i].context.IntAt);
197
 
          GC_push_one ((word) thread_table[i].context.IntV0);
198
 
          GC_push_one ((word) thread_table[i].context.IntV1);
199
 
          GC_push_one ((word) thread_table[i].context.IntA0);
200
 
          GC_push_one ((word) thread_table[i].context.IntA1);
201
 
          GC_push_one ((word) thread_table[i].context.IntA2);
202
 
          GC_push_one ((word) thread_table[i].context.IntA3);
203
 
          GC_push_one ((word) thread_table[i].context.IntT0);
204
 
          GC_push_one ((word) thread_table[i].context.IntT1);
205
 
          GC_push_one ((word) thread_table[i].context.IntT2);
206
 
          GC_push_one ((word) thread_table[i].context.IntT3);
207
 
          GC_push_one ((word) thread_table[i].context.IntT4);
208
 
          GC_push_one ((word) thread_table[i].context.IntT5);
209
 
          GC_push_one ((word) thread_table[i].context.IntT6);
210
 
          GC_push_one ((word) thread_table[i].context.IntT7);
211
 
          GC_push_one ((word) thread_table[i].context.IntS0);
212
 
          GC_push_one ((word) thread_table[i].context.IntS1);
213
 
          GC_push_one ((word) thread_table[i].context.IntS2);
214
 
          GC_push_one ((word) thread_table[i].context.IntS3);
215
 
          GC_push_one ((word) thread_table[i].context.IntS4);
216
 
          GC_push_one ((word) thread_table[i].context.IntS5);
217
 
          GC_push_one ((word) thread_table[i].context.IntS6);
218
 
          GC_push_one ((word) thread_table[i].context.IntS7);
219
 
          GC_push_one ((word) thread_table[i].context.IntT8);
220
 
          GC_push_one ((word) thread_table[i].context.IntT9);
221
 
          GC_push_one ((word) thread_table[i].context.IntK0);
222
 
          GC_push_one ((word) thread_table[i].context.IntK1);
223
 
          GC_push_one ((word) thread_table[i].context.IntS8);
224
 
          GC_push_all_stack((char *) thread_table[i].context.IntSp,
225
 
                            thread_table[i].stack);
226
 
#       else
227
 
#       ifdef PPC
228
 
          if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack
229
 
              || thread_table[i].context.Gpr1 < (DWORD)bottom)
230
 
              ABORT("Thread stack pointer out of range");
231
 
          GC_push_one ((word) thread_table[i].context.Gpr0);
232
 
          /* Gpr1 is stack pointer */
233
 
          /* Gpr2 is global pointer */
234
 
          GC_push_one ((word) thread_table[i].context.Gpr3);
235
 
          GC_push_one ((word) thread_table[i].context.Gpr4);
236
 
          GC_push_one ((word) thread_table[i].context.Gpr5);
237
 
          GC_push_one ((word) thread_table[i].context.Gpr6);
238
 
          GC_push_one ((word) thread_table[i].context.Gpr7);
239
 
          GC_push_one ((word) thread_table[i].context.Gpr8);
240
 
          GC_push_one ((word) thread_table[i].context.Gpr9);
241
 
          GC_push_one ((word) thread_table[i].context.Gpr10);
242
 
          GC_push_one ((word) thread_table[i].context.Gpr11);
243
 
          GC_push_one ((word) thread_table[i].context.Gpr12);
244
 
          /* Gpr13 is reserved for the kernel */
245
 
          GC_push_one ((word) thread_table[i].context.Gpr14);
246
 
          GC_push_one ((word) thread_table[i].context.Gpr15);
247
 
          GC_push_one ((word) thread_table[i].context.Gpr16);
248
 
          GC_push_one ((word) thread_table[i].context.Gpr17);
249
 
          GC_push_one ((word) thread_table[i].context.Gpr18);
250
 
          GC_push_one ((word) thread_table[i].context.Gpr19);
251
 
          GC_push_one ((word) thread_table[i].context.Gpr20);
252
 
          GC_push_one ((word) thread_table[i].context.Gpr21);
253
 
          GC_push_one ((word) thread_table[i].context.Gpr22);
254
 
          GC_push_one ((word) thread_table[i].context.Gpr23);
255
 
          GC_push_one ((word) thread_table[i].context.Gpr24);
256
 
          GC_push_one ((word) thread_table[i].context.Gpr25);
257
 
          GC_push_one ((word) thread_table[i].context.Gpr26);
258
 
          GC_push_one ((word) thread_table[i].context.Gpr27);
259
 
          GC_push_one ((word) thread_table[i].context.Gpr28);
260
 
          GC_push_one ((word) thread_table[i].context.Gpr29);
261
 
          GC_push_one ((word) thread_table[i].context.Gpr30);
262
 
          GC_push_one ((word) thread_table[i].context.Gpr31);
263
 
          GC_push_all_stack((char *) thread_table[i].context.Gpr1,
264
 
                            thread_table[i].stack);
265
 
#       else
266
 
#       ifdef ALPHA
267
 
          if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
268
 
              || thread_table[i].context.IntSp < (DWORD)bottom)
269
 
              ABORT("Thread stack pointer out of range");
270
 
          GC_push_one ((word) thread_table[i].context.IntV0);
271
 
          GC_push_one ((word) thread_table[i].context.IntT0);
272
 
          GC_push_one ((word) thread_table[i].context.IntT1);
273
 
          GC_push_one ((word) thread_table[i].context.IntT2);
274
 
          GC_push_one ((word) thread_table[i].context.IntT3);
275
 
          GC_push_one ((word) thread_table[i].context.IntT4);
276
 
          GC_push_one ((word) thread_table[i].context.IntT5);
277
 
          GC_push_one ((word) thread_table[i].context.IntT6);
278
 
          GC_push_one ((word) thread_table[i].context.IntT7);
279
 
          GC_push_one ((word) thread_table[i].context.IntS0);
280
 
          GC_push_one ((word) thread_table[i].context.IntS1);
281
 
          GC_push_one ((word) thread_table[i].context.IntS2);
282
 
          GC_push_one ((word) thread_table[i].context.IntS3);
283
 
          GC_push_one ((word) thread_table[i].context.IntS4);
284
 
          GC_push_one ((word) thread_table[i].context.IntS5);
285
 
          GC_push_one ((word) thread_table[i].context.IntFp);
286
 
          GC_push_one ((word) thread_table[i].context.IntA0);
287
 
          GC_push_one ((word) thread_table[i].context.IntA1);
288
 
          GC_push_one ((word) thread_table[i].context.IntA2);
289
 
          GC_push_one ((word) thread_table[i].context.IntA3);
290
 
          GC_push_one ((word) thread_table[i].context.IntA4);
291
 
          GC_push_one ((word) thread_table[i].context.IntA5);
292
 
          GC_push_one ((word) thread_table[i].context.IntT8);
293
 
          GC_push_one ((word) thread_table[i].context.IntT9);
294
 
          GC_push_one ((word) thread_table[i].context.IntT10);
295
 
          GC_push_one ((word) thread_table[i].context.IntT11);
296
 
          GC_push_one ((word) thread_table[i].context.IntT12);
297
 
          GC_push_one ((word) thread_table[i].context.IntAt);
298
 
          GC_push_all_stack((char *) thread_table[i].context.IntSp,
299
 
                            thread_table[i].stack);
300
 
#       else
301
 
              --> architecture not supported
302
 
#       endif /* !ALPHA */
303
 
#       endif /* !PPC */
304
 
#       endif /* !MIPS */
305
 
#       endif /* !SHx */
306
 
#       endif /* !ARM32 */
307
 
#       endif /* !I386 */
 
396
        WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
 
397
             (unsigned long)sp);
 
398
        GC_push_all_stack(stack_min, thread->stack_base);
308
399
      }
309
400
    }
 
401
  }
 
402
  if (!found_me) ABORT("Collecting from unknown thread.");
310
403
}
311
404
 
312
405
void GC_get_next_stack(char *start, char **lo, char **hi)
314
407
    int i;
315
408
#   define ADDR_LIMIT (char *)(-1L)
316
409
    char * current_min = ADDR_LIMIT;
317
 
 
318
 
    for (i = 0; i < MAX_THREADS; i++) {
319
 
        char * s = (char *)thread_table[i].stack;
 
410
    LONG my_max = GC_get_max_thread_index();
 
411
  
 
412
    for (i = 0; i <= my_max; i++) {
 
413
        char * s = (char *)thread_table[i].stack_base;
320
414
 
321
415
        if (0 != s && s > start && s < current_min) {
322
416
            current_min = s;
327
421
        *lo = ADDR_LIMIT;
328
422
        return;
329
423
    }
330
 
    *lo = GC_get_lo_stack_addr(current_min);
 
424
    *lo = GC_get_stack_min(current_min);
331
425
    if (*lo < start) *lo = start;
332
426
}
333
427
 
334
 
#if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))
335
 
 
336
 
HANDLE WINAPI GC_CreateThread(
 
428
#if !defined(CYGWIN32)
 
429
 
 
430
#if !defined(MSWINCE) && defined(GC_DLL)
 
431
 
 
432
/* We register threads from DllMain */
 
433
 
 
434
GC_API HANDLE WINAPI GC_CreateThread(
337
435
    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
338
436
    DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
339
437
    LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
342
440
                        lpParameter, dwCreationFlags, lpThreadId);
343
441
}
344
442
 
345
 
#else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))  */
 
443
#else /* defined(MSWINCE) || !defined(GC_DLL))  */
 
444
 
 
445
/* We have no DllMain to take care of new threads.  Thus we     */
 
446
/* must properly intercept thread creation.                     */
346
447
 
347
448
typedef struct {
348
 
    HANDLE child_ready_h, parent_ready_h;
349
 
    volatile struct thread_entry * entry;
350
449
    LPTHREAD_START_ROUTINE start;
351
450
    LPVOID param;
352
451
} thread_args;
353
452
 
354
 
DWORD WINAPI thread_start(LPVOID arg);
 
453
static DWORD WINAPI thread_start(LPVOID arg);
355
454
 
356
 
HANDLE WINAPI GC_CreateThread(
 
455
GC_API HANDLE WINAPI GC_CreateThread(
357
456
    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
358
457
    DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
359
458
    LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
360
459
{
361
460
    HANDLE thread_h = NULL;
362
 
    HANDLE child_ready_h, parent_ready_h;
363
 
 
364
 
    int i;
365
 
    thread_args args;
366
 
 
367
 
    /* allocate thread slot */
368
 
    LOCK();
369
 
    for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
370
 
        ;
371
 
    if (i != MAX_THREADS) {
372
 
        thread_table[i].in_use = TRUE;
373
 
    }
374
 
    UNLOCK();
375
 
 
376
 
    if (i != MAX_THREADS) {
377
 
 
378
 
        /* create unnamed unsignalled events */
379
 
        if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
380
 
            if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
381
 
 
382
 
                /* set up thread arguments */
383
 
                args.child_ready_h = child_ready_h;
384
 
                args.parent_ready_h = parent_ready_h;
385
 
                args.entry = &thread_table[i];
386
 
                args.start = lpStartAddress;
387
 
                args.param = lpParameter;
388
 
 
389
 
                thread_h = CreateThread(lpThreadAttributes,
390
 
                                        dwStackSize, thread_start,
391
 
                                        &args,
392
 
                                        dwCreationFlags & ~CREATE_SUSPENDED,
393
 
                                        lpThreadId);
394
 
 
395
 
                if (thread_h) {
396
 
 
397
 
                    /* fill in ID and handle; tell child this is done */
398
 
                    thread_table[i].id = *lpThreadId;
399
 
                    thread_table[i].handle = thread_h;
400
 
                    SetEvent (parent_ready_h);
401
 
 
402
 
                    /* wait for child to fill in stack and copy args */
403
 
                    WaitForSingleObject (child_ready_h, INFINITE);
404
 
 
405
 
                    /* suspend the child if requested */
406
 
                    if (dwCreationFlags & CREATE_SUSPENDED)
407
 
                        SuspendThread (thread_h);
408
 
 
409
 
                    /* let child call given function now (or when resumed) */
410
 
                    SetEvent (parent_ready_h);
411
 
 
412
 
                } else {
413
 
                    CloseHandle (parent_ready_h);
414
 
                }
415
 
            }
416
 
        }
417
 
 
418
 
        CloseHandle (child_ready_h);
419
 
 
420
 
        if (thread_h == NULL)
421
 
            thread_table[i].in_use = FALSE;
422
 
 
423
 
    } else { /* no thread slot found */
424
 
        SetLastError (ERROR_TOO_MANY_TCBS);
425
 
    }
 
461
 
 
462
    thread_args *args;
 
463
 
 
464
    if (!GC_is_initialized) GC_init();
 
465
                /* make sure GC is initialized (i.e. main thread is attached) */
 
466
    
 
467
    args = GC_malloc_uncollectable(sizeof(thread_args)); 
 
468
        /* Handed off to and deallocated by child thread.       */
 
469
    if (0 == args) {
 
470
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 
471
        return NULL;
 
472
    }
 
473
 
 
474
    /* set up thread arguments */
 
475
        args -> start = lpStartAddress;
 
476
        args -> param = lpParameter;
 
477
 
 
478
    thread_h = CreateThread(lpThreadAttributes,
 
479
                            dwStackSize, thread_start,
 
480
                            args, dwCreationFlags,
 
481
                            lpThreadId);
426
482
 
427
483
    return thread_h;
428
484
}
430
486
static DWORD WINAPI thread_start(LPVOID arg)
431
487
{
432
488
    DWORD ret = 0;
433
 
    thread_args args = *(thread_args *)arg;
434
 
 
435
 
    /* wait for parent to fill in ID and handle */
436
 
    WaitForSingleObject (args.parent_ready_h, INFINITE);
437
 
    ResetEvent (args.parent_ready_h);
438
 
 
439
 
    /* fill in stack; tell parent this is done */
440
 
    args.entry->stack = GC_get_stack_base();
441
 
    SetEvent (args.child_ready_h);
442
 
 
443
 
    /* wait for parent to tell us to go (in case it needs to suspend us) */
444
 
    WaitForSingleObject (args.parent_ready_h, INFINITE);
445
 
    CloseHandle (args.parent_ready_h);
 
489
    thread_args *args = (thread_args *)arg;
 
490
 
 
491
    GC_new_thread();
446
492
 
447
493
    /* Clear the thread entry even if we exit with an exception.        */
448
494
    /* This is probably pointless, since an uncaught exception is       */
449
495
    /* supposed to result in the process being killed.                  */
 
496
#ifndef __GNUC__
450
497
    __try {
451
 
        ret = args.start (args.param);
 
498
#endif /* __GNUC__ */
 
499
        ret = args->start (args->param);
 
500
#ifndef __GNUC__
452
501
    } __finally {
453
 
        LOCK();
454
 
        args.entry->stack = 0;
455
 
        args.entry->in_use = FALSE;
456
 
              /* cast away volatile qualifier */
457
 
        BZERO((void *) &args.entry->context, sizeof(CONTEXT));
458
 
        UNLOCK();
 
502
#endif /* __GNUC__ */
 
503
        GC_free(args);
 
504
        GC_delete_thread(GetCurrentThreadId());
 
505
#ifndef __GNUC__
459
506
    }
 
507
#endif /* __GNUC__ */
460
508
 
461
509
    return ret;
462
510
}
463
511
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))  */
464
512
 
 
513
#endif /* !CYGWIN32 */
 
514
 
465
515
#ifdef MSWINCE
466
516
 
467
517
typedef struct {
485
535
    DWORD thread_id;
486
536
 
487
537
    /* initialize everything */
488
 
    InitializeCriticalSection(&GC_allocate_ml);
489
538
    GC_init();
490
539
 
491
540
    /* start the main thread */
515
564
 
516
565
# else /* !MSWINCE */
517
566
 
518
 
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
 
567
/* Called by GC_init() - we hold the allocation lock.   */
 
568
void GC_thr_init() {
 
569
    if (GC_thr_initialized) return;
 
570
    GC_main_thread = GetCurrentThreadId();
 
571
    GC_thr_initialized = TRUE;
 
572
 
 
573
    /* Add the initial thread, so we can stop it.       */
 
574
    GC_new_thread();
 
575
}
 
576
 
 
577
#ifdef CYGWIN32
 
578
 
 
579
struct start_info {
 
580
    void *(*start_routine)(void *);
 
581
    void *arg;
 
582
    GC_bool detached;
 
583
};
 
584
 
 
585
int GC_pthread_join(pthread_t pthread_id, void **retval) {
 
586
    int result;
 
587
    int i;
 
588
    GC_thread me;
 
589
 
 
590
#   if DEBUG_CYGWIN_THREADS
 
591
      GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",
 
592
                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
 
593
#   endif
 
594
 
 
595
    /* Thread being joined might not have registered itself yet. */
 
596
    /* After the join,thread id may have been recycled.          */
 
597
    /* FIXME: It would be better if this worked more like        */
 
598
    /* pthread_support.c.                                        */
 
599
 
 
600
    while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10);
 
601
 
 
602
    result = pthread_join(pthread_id, retval);
 
603
 
 
604
    GC_delete_gc_thread(me);
 
605
 
 
606
#   if DEBUG_CYGWIN_THREADS
 
607
      GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
 
608
                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
 
609
#   endif
 
610
 
 
611
    return result;
 
612
}
 
613
 
 
614
/* Cygwin-pthreads calls CreateThread internally, but it's not
 
615
 * easily interceptible by us..
 
616
 *   so intercept pthread_create instead
 
617
 */
 
618
int
 
619
GC_pthread_create(pthread_t *new_thread,
 
620
                  const pthread_attr_t *attr,
 
621
                  void *(*start_routine)(void *), void *arg) {
 
622
    int result;
 
623
    struct start_info * si;
 
624
 
 
625
    if (!GC_is_initialized) GC_init();
 
626
                /* make sure GC is initialized (i.e. main thread is attached) */
 
627
    
 
628
    /* This is otherwise saved only in an area mmapped by the thread */
 
629
    /* library, which isn't visible to the collector.            */
 
630
    si = GC_malloc_uncollectable(sizeof(struct start_info)); 
 
631
    if (0 == si) return(EAGAIN);
 
632
 
 
633
    si -> start_routine = start_routine;
 
634
    si -> arg = arg;
 
635
    if (attr != 0 &&
 
636
        pthread_attr_getdetachstate(attr, &si->detached)
 
637
        == PTHREAD_CREATE_DETACHED) {
 
638
      si->detached = TRUE;
 
639
    }
 
640
 
 
641
#   if DEBUG_CYGWIN_THREADS
 
642
      GC_printf2("About to create a thread from 0x%x(0x%x)\n",
 
643
                 (int)pthread_self(), GetCurrentThreadId);
 
644
#   endif
 
645
    result = pthread_create(new_thread, attr, GC_start_routine, si); 
 
646
 
 
647
    if (result) { /* failure */
 
648
        GC_free(si);
 
649
    } 
 
650
 
 
651
    return(result);
 
652
}
 
653
 
 
654
void * GC_start_routine(void * arg)
 
655
{
 
656
    struct start_info * si = arg;
 
657
    void * result;
 
658
    void *(*start)(void *);
 
659
    void *start_arg;
 
660
    pthread_t pthread_id;
 
661
    GC_thread me;
 
662
    GC_bool detached;
 
663
    int i;
 
664
 
 
665
#   if DEBUG_CYGWIN_THREADS
 
666
      GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
 
667
                                                   GetCurrentThreadId());
 
668
#   endif
 
669
 
 
670
    /* If a GC occurs before the thread is registered, that GC will     */
 
671
    /* ignore this thread.  That's fine, since it will block trying to  */
 
672
    /* acquire the allocation lock, and won't yet hold interesting      */
 
673
    /* pointers.                                                        */
 
674
    LOCK();
 
675
    /* We register the thread here instead of in the parent, so that    */
 
676
    /* we don't need to hold the allocation lock during pthread_create. */
 
677
    me = GC_new_thread();
 
678
    UNLOCK();
 
679
 
 
680
    start = si -> start_routine;
 
681
    start_arg = si -> arg;
 
682
    if (si-> detached) me -> flags |= DETACHED;
 
683
    me -> pthread_id = pthread_id = pthread_self();
 
684
 
 
685
    GC_free(si); /* was allocated uncollectable */
 
686
 
 
687
    pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
 
688
    result = (*start)(start_arg);
 
689
    me -> status = result;
 
690
    pthread_cleanup_pop(0);
 
691
 
 
692
#   if DEBUG_CYGWIN_THREADS
 
693
      GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
 
694
                 (int)pthread_self(),GetCurrentThreadId());
 
695
#   endif
 
696
 
 
697
    return(result);
 
698
}
 
699
 
 
700
void GC_thread_exit_proc(void *arg)
 
701
{
 
702
    GC_thread me = (GC_thread)arg;
 
703
    int i;
 
704
 
 
705
#   if DEBUG_CYGWIN_THREADS
 
706
      GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
 
707
                 (int)pthread_self(),GetCurrentThreadId());
 
708
#   endif
 
709
 
 
710
    LOCK();
 
711
    if (me -> flags & DETACHED) {
 
712
      GC_delete_thread(GetCurrentThreadId());
 
713
    } else {
 
714
      /* deallocate it as part of join */
 
715
      me -> flags |= FINISHED;
 
716
    }
 
717
    UNLOCK();
 
718
}
 
719
 
 
720
/* nothing required here... */
 
721
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
 
722
  return pthread_sigmask(how, set, oset);
 
723
}
 
724
 
 
725
int GC_pthread_detach(pthread_t thread)
 
726
{
 
727
    int result;
 
728
    GC_thread thread_gc_id;
 
729
    
 
730
    LOCK();
 
731
    thread_gc_id = GC_lookup_thread(thread);
 
732
    UNLOCK();
 
733
    result = pthread_detach(thread);
 
734
    if (result == 0) {
 
735
      LOCK();
 
736
      thread_gc_id -> flags |= DETACHED;
 
737
      /* Here the pthread thread id may have been recycled. */
 
738
      if (thread_gc_id -> flags & FINISHED) {
 
739
        GC_delete_gc_thread(thread_gc_id);
 
740
      }
 
741
      UNLOCK();
 
742
    }
 
743
    return result;
 
744
}
 
745
 
 
746
#else /* !CYGWIN32 */
519
747
 
520
748
/*
521
 
 * This isn't generally safe, since DllMain is not premptible.
522
 
 * If another thread holds the lock while this runs we're in trouble.
 
749
 * We avoid acquiring locks here, since this doesn't seem to be preemptable.
523
750
 * Pontus Rydin suggests wrapping the thread start routine instead.
524
751
 */
 
752
#ifdef GC_DLL
525
753
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
526
754
{
527
755
  switch (reason) {
528
756
  case DLL_PROCESS_ATTACH:
529
 
    InitializeCriticalSection(&GC_allocate_ml);
530
757
    GC_init();  /* Force initialization before thread attach.   */
531
758
    /* fall through */
532
759
  case DLL_THREAD_ATTACH:
533
 
    {
534
 
      int i;
535
 
      /* It appears to be unsafe to acquire a lock here, since this     */
536
 
      /* code is apparently not preeemptible on some systems.           */
537
 
      /* (This is based on complaints, not on Microsoft's official      */
538
 
      /* documentation, which says this should perform "only simple     */
539
 
      /* inititalization tasks".)                                       */
540
 
      /* Hence we make do with nonblocking synchronization.             */
541
 
 
542
 
      /* The following should be a noop according to the win32  */
543
 
      /* documentation.  There is empirical evidence that it    */
544
 
      /* isn't.         - HB                                    */
545
 
#     ifdef MPROTECT_VDB
546
 
       if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
547
 
#     endif
548
 
 
549
 
      for (i = 0;
550
 
                               /* cast away volatile qualifier */
551
 
           InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
552
 
           i++) {
553
 
        /* Compare-and-swap would make this cleaner, but that's not     */
554
 
        /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */
555
 
        /* InterlockedExchange is supposed to be replaced by            */
556
 
        /* InterlockedExchangePointer, but that's not really what I     */
557
 
        /* want here.                                                   */
558
 
        if (i == MAX_THREADS - 1)
559
 
          ABORT("too many threads");
560
 
      }
561
 
      thread_table[i].id = GetCurrentThreadId();
562
 
      if (!DuplicateHandle(GetCurrentProcess(),
563
 
                           GetCurrentThread(),
564
 
                           GetCurrentProcess(),
565
 
                           /* cast away volatile qualifier */
566
 
                           (HANDLE *) &thread_table[i].handle,
567
 
                           0,
568
 
                           0,
569
 
                           DUPLICATE_SAME_ACCESS)) {
570
 
        DWORD last_error = GetLastError();
571
 
        GC_printf1("Last error code: %lx\n", last_error);
572
 
        ABORT("DuplicateHandle failed");
573
 
      }
574
 
      thread_table[i].stack = GC_get_stack_base();
575
 
      /* If this thread is being created while we are trying to stop    */
576
 
      /* the world, wait here.  Hopefully this can't happen on any      */
577
 
      /* systems that don't allow us to block here.                     */
578
 
      while (GC_please_stop) Sleep(20);
579
 
    }
 
760
    GC_ASSERT(GC_thr_initialized);
 
761
    if (GC_main_thread != GetCurrentThreadId()) {
 
762
        GC_new_thread();
 
763
    } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
580
764
    break;
 
765
 
581
766
  case DLL_THREAD_DETACH:
582
 
    {
583
 
      int i;
584
 
      DWORD thread_id = GetCurrentThreadId();
585
 
      LOCK();
586
 
      for (i = 0;
587
 
           i < MAX_THREADS &&
588
 
           (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
589
 
           i++) {}
590
 
      if (i >= MAX_THREADS) {
591
 
          WARN("thread %ld not found on detach", (GC_word)thread_id);
592
 
      } else {
593
 
          thread_table[i].stack = 0;
594
 
          thread_table[i].in_use = FALSE;
595
 
          CloseHandle(thread_table[i].handle);
596
 
            /* cast away volatile qualifier */
597
 
          BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
598
 
      }
599
 
      UNLOCK();
600
 
    }
 
767
    GC_delete_thread(GetCurrentThreadId());
601
768
    break;
 
769
 
602
770
  case DLL_PROCESS_DETACH:
603
771
    {
604
772
      int i;
605
773
 
606
774
      LOCK();
607
 
      for (i = 0; i < MAX_THREADS; ++i)
 
775
      for (i = 0; i <= GC_get_max_thread_index(); ++i)
608
776
      {
609
777
          if (thread_table[i].in_use)
610
 
          {
611
 
              thread_table[i].stack = 0;
612
 
              thread_table[i].in_use = FALSE;
613
 
              CloseHandle(thread_table[i].handle);
614
 
              BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
615
 
          }
 
778
            GC_delete_gc_thread(thread_table + i);
616
779
      }
617
780
      UNLOCK();
618
781
 
624
787
  }
625
788
  return TRUE;
626
789
}
 
790
#endif /* GC_DLL */
 
791
#endif /* !CYGWIN32 */
627
792
 
628
793
# endif /* !MSWINCE */
629
794