]> git.ipfire.org Git - thirdparty/gcc.git/blob - boehm-gc/win32_threads.c
Makefile.am: Added win32_threads.c to sources list.
[thirdparty/gcc.git] / boehm-gc / win32_threads.c
1 #if defined(GC_WIN32_THREADS)
2
3 #include "private/gc_priv.h"
4
5 #if 0
6 #define STRICT
7 #include <windows.h>
8 #endif
9
10 #define MAX_THREADS 64
11
12 struct thread_entry {
13 LONG in_use;
14 DWORD id;
15 HANDLE handle;
16 void *stack; /* The cold end of the stack. */
17 /* 0 ==> entry not valid. */
18 /* !in_use ==> stack == 0 */
19 CONTEXT context;
20 GC_bool suspended;
21 };
22
23 volatile GC_bool GC_please_stop = FALSE;
24
25 volatile struct thread_entry thread_table[MAX_THREADS];
26
27 void GC_push_thread_structures GC_PROTO((void))
28 {
29 /* Unlike the other threads implementations, the thread table here */
30 /* contains no pointers to the collectable heap. Thus we have */
31 /* no private structures we need to preserve. */
32 }
33
34 void GC_stop_world()
35 {
36 DWORD thread_id = GetCurrentThreadId();
37 int i;
38
39 GC_please_stop = TRUE;
40 for (i = 0; i < MAX_THREADS; i++)
41 if (thread_table[i].stack != 0
42 && thread_table[i].id != thread_id) {
43 # ifdef MSWINCE
44 /* SuspendThread will fail if thread is running kernel code */
45 while (SuspendThread(thread_table[i].handle) == (DWORD)-1)
46 Sleep(10);
47 # else
48 /* Apparently the Windows 95 GetOpenFileName call creates */
49 /* a thread that does not properly get cleaned up, and */
50 /* SuspendThread on its descriptor may provoke a crash. */
51 /* This reduces the probability of that event, though it still */
52 /* appears there's a race here. */
53 DWORD exitCode;
54 if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
55 exitCode != STILL_ACTIVE) {
56 thread_table[i].stack = 0;
57 thread_table[i].in_use = FALSE;
58 CloseHandle(thread_table[i].handle);
59 BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
60 continue;
61 }
62 if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
63 ABORT("SuspendThread failed");
64 # endif
65 thread_table[i].suspended = TRUE;
66 }
67 }
68
69 void GC_start_world()
70 {
71 DWORD thread_id = GetCurrentThreadId();
72 int i;
73 for (i = 0; i < MAX_THREADS; i++)
74 if (thread_table[i].stack != 0 && thread_table[i].suspended
75 && thread_table[i].id != thread_id) {
76 if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
77 ABORT("ResumeThread failed");
78 thread_table[i].suspended = FALSE;
79 }
80 GC_please_stop = FALSE;
81 }
82
83 # ifdef _MSC_VER
84 # pragma warning(disable:4715)
85 # endif
86 ptr_t GC_current_stackbottom()
87 {
88 DWORD thread_id = GetCurrentThreadId();
89 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;
93 ABORT("no thread table entry for current thread");
94 }
95 # ifdef _MSC_VER
96 # pragma warning(default:4715)
97 # endif
98
99 # ifdef MSWINCE
100 /* The VirtualQuery calls below won't work properly on WinCE, but */
101 /* since each stack is restricted to an aligned 64K region of */
102 /* virtual memory we can just take the next lowest multiple of 64K. */
103 # define GC_get_lo_stack_addr(s) \
104 ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
105 # else
106 static ptr_t GC_get_lo_stack_addr(ptr_t s)
107 {
108 ptr_t bottom;
109 MEMORY_BASIC_INFORMATION info;
110 VirtualQuery(s, &info, sizeof(info));
111 do {
112 bottom = info.BaseAddress;
113 VirtualQuery(bottom - 1, &info, sizeof(info));
114 } while ((info.Protect & PAGE_READWRITE)
115 && !(info.Protect & PAGE_GUARD));
116 return(bottom);
117 }
118 # endif
119
120 void GC_push_all_stacks()
121 {
122 DWORD thread_id = GetCurrentThreadId();
123 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);
129 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 */
308 }
309 }
310 }
311
312 void GC_get_next_stack(char *start, char **lo, char **hi)
313 {
314 int i;
315 # define ADDR_LIMIT (char *)(-1L)
316 char * current_min = ADDR_LIMIT;
317
318 for (i = 0; i < MAX_THREADS; i++) {
319 char * s = (char *)thread_table[i].stack;
320
321 if (0 != s && s > start && s < current_min) {
322 current_min = s;
323 }
324 }
325 *hi = current_min;
326 if (current_min == ADDR_LIMIT) {
327 *lo = ADDR_LIMIT;
328 return;
329 }
330 *lo = GC_get_lo_stack_addr(current_min);
331 if (*lo < start) *lo = start;
332 }
333
334 #if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))
335
336 HANDLE WINAPI GC_CreateThread(
337 LPSECURITY_ATTRIBUTES lpThreadAttributes,
338 DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
339 LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
340 {
341 return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
342 lpParameter, dwCreationFlags, lpThreadId);
343 }
344
345 #else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
346
347 typedef struct {
348 HANDLE child_ready_h, parent_ready_h;
349 volatile struct thread_entry * entry;
350 LPTHREAD_START_ROUTINE start;
351 LPVOID param;
352 } thread_args;
353
354 DWORD WINAPI thread_start(LPVOID arg);
355
356 HANDLE WINAPI GC_CreateThread(
357 LPSECURITY_ATTRIBUTES lpThreadAttributes,
358 DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
359 LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
360 {
361 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 }
426
427 return thread_h;
428 }
429
430 static DWORD WINAPI thread_start(LPVOID arg)
431 {
432 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);
446
447 /* Clear the thread entry even if we exit with an exception. */
448 /* This is probably pointless, since an uncaught exception is */
449 /* supposed to result in the process being killed. */
450 __try {
451 ret = args.start (args.param);
452 } __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();
459 }
460
461 return ret;
462 }
463 #endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
464
465 #ifdef MSWINCE
466
467 typedef struct {
468 HINSTANCE hInstance;
469 HINSTANCE hPrevInstance;
470 LPWSTR lpCmdLine;
471 int nShowCmd;
472 } main_thread_args;
473
474 DWORD WINAPI main_thread_start(LPVOID arg);
475
476 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
477 LPWSTR lpCmdLine, int nShowCmd)
478 {
479 DWORD exit_code = 1;
480
481 main_thread_args args = {
482 hInstance, hPrevInstance, lpCmdLine, nShowCmd
483 };
484 HANDLE thread_h;
485 DWORD thread_id;
486
487 /* initialize everything */
488 InitializeCriticalSection(&GC_allocate_ml);
489 GC_init();
490
491 /* start the main thread */
492 thread_h = GC_CreateThread(
493 NULL, 0, main_thread_start, &args, 0, &thread_id);
494
495 if (thread_h != NULL)
496 {
497 WaitForSingleObject (thread_h, INFINITE);
498 GetExitCodeThread (thread_h, &exit_code);
499 CloseHandle (thread_h);
500 }
501
502 GC_deinit();
503 DeleteCriticalSection(&GC_allocate_ml);
504
505 return (int) exit_code;
506 }
507
508 DWORD WINAPI main_thread_start(LPVOID arg)
509 {
510 main_thread_args * args = (main_thread_args *) arg;
511
512 return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
513 args->lpCmdLine, args->nShowCmd);
514 }
515
516 # else /* !MSWINCE */
517
518 LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
519
520 /*
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.
523 * Pontus Rydin suggests wrapping the thread start routine instead.
524 */
525 BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
526 {
527 switch (reason) {
528 case DLL_PROCESS_ATTACH:
529 InitializeCriticalSection(&GC_allocate_ml);
530 GC_init(); /* Force initialization before thread attach. */
531 /* fall through */
532 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 }
580 break;
581 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 }
601 break;
602 case DLL_PROCESS_DETACH:
603 {
604 int i;
605
606 LOCK();
607 for (i = 0; i < MAX_THREADS; ++i)
608 {
609 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 }
616 }
617 UNLOCK();
618
619 GC_deinit();
620 DeleteCriticalSection(&GC_allocate_ml);
621 }
622 break;
623
624 }
625 return TRUE;
626 }
627
628 # endif /* !MSWINCE */
629
630 #endif /* GC_WIN32_THREADS */