Daily bump.
[official-gcc.git] / boehm-gc / win32_threads.c
blobd5e3920cbe4cb2a0ed1e60c2e2fa8dc0066e1e95
1 #if defined(GC_WIN32_THREADS)
3 #include "private/gc_priv.h"
5 #if 0
6 #define STRICT
7 #include <windows.h>
8 #endif
10 #define MAX_THREADS 64
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;
23 volatile GC_bool GC_please_stop = FALSE;
25 volatile struct thread_entry thread_table[MAX_THREADS];
27 void GC_push_thread_structures GC_PROTO((void))
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. */
34 void GC_stop_world()
36 DWORD thread_id = GetCurrentThreadId();
37 int i;
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;
62 if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
63 ABORT("SuspendThread failed");
64 # endif
65 thread_table[i].suspended = TRUE;
69 void GC_start_world()
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;
80 GC_please_stop = FALSE;
83 # ifdef _MSC_VER
84 # pragma warning(disable:4715)
85 # endif
86 ptr_t GC_current_stackbottom()
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");
95 # ifdef _MSC_VER
96 # pragma warning(default:4715)
97 # endif
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)
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);
118 # endif
120 void GC_push_all_stacks()
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 if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
148 || thread_table[i].context.Esp < (DWORD)bottom) {
149 WARN("Thread stack pointer 0x%lx out of range, pushing everything",
150 thread_table[i].context.Esp);
151 GC_push_all_stack((char *) bottom, thread_table[i].stack);
152 } else {
153 GC_push_all_stack((char *) thread_table[i].context.Esp,
154 thread_table[i].stack);
156 # else
157 # ifdef ARM32
158 if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack
159 || thread_table[i].context.Sp < (DWORD)bottom)
160 ABORT("Thread stack pointer out of range");
161 GC_push_one ((word) thread_table[i].context.R0);
162 GC_push_one ((word) thread_table[i].context.R1);
163 GC_push_one ((word) thread_table[i].context.R2);
164 GC_push_one ((word) thread_table[i].context.R3);
165 GC_push_one ((word) thread_table[i].context.R4);
166 GC_push_one ((word) thread_table[i].context.R5);
167 GC_push_one ((word) thread_table[i].context.R6);
168 GC_push_one ((word) thread_table[i].context.R7);
169 GC_push_one ((word) thread_table[i].context.R8);
170 GC_push_one ((word) thread_table[i].context.R9);
171 GC_push_one ((word) thread_table[i].context.R10);
172 GC_push_one ((word) thread_table[i].context.R11);
173 GC_push_one ((word) thread_table[i].context.R12);
174 GC_push_all_stack((char *) thread_table[i].context.Sp,
175 thread_table[i].stack);
176 # else
177 # ifdef SHx
178 if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack
179 || thread_table[i].context.R15 < (DWORD)bottom)
180 ABORT("Thread stack pointer out of range");
181 GC_push_one ((word) thread_table[i].context.R0);
182 GC_push_one ((word) thread_table[i].context.R1);
183 GC_push_one ((word) thread_table[i].context.R2);
184 GC_push_one ((word) thread_table[i].context.R3);
185 GC_push_one ((word) thread_table[i].context.R4);
186 GC_push_one ((word) thread_table[i].context.R5);
187 GC_push_one ((word) thread_table[i].context.R6);
188 GC_push_one ((word) thread_table[i].context.R7);
189 GC_push_one ((word) thread_table[i].context.R8);
190 GC_push_one ((word) thread_table[i].context.R9);
191 GC_push_one ((word) thread_table[i].context.R10);
192 GC_push_one ((word) thread_table[i].context.R11);
193 GC_push_one ((word) thread_table[i].context.R12);
194 GC_push_one ((word) thread_table[i].context.R13);
195 GC_push_one ((word) thread_table[i].context.R14);
196 GC_push_all_stack((char *) thread_table[i].context.R15,
197 thread_table[i].stack);
198 # else
199 # ifdef MIPS
200 if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
201 || thread_table[i].context.IntSp < (DWORD)bottom)
202 ABORT("Thread stack pointer out of range");
203 GC_push_one ((word) thread_table[i].context.IntAt);
204 GC_push_one ((word) thread_table[i].context.IntV0);
205 GC_push_one ((word) thread_table[i].context.IntV1);
206 GC_push_one ((word) thread_table[i].context.IntA0);
207 GC_push_one ((word) thread_table[i].context.IntA1);
208 GC_push_one ((word) thread_table[i].context.IntA2);
209 GC_push_one ((word) thread_table[i].context.IntA3);
210 GC_push_one ((word) thread_table[i].context.IntT0);
211 GC_push_one ((word) thread_table[i].context.IntT1);
212 GC_push_one ((word) thread_table[i].context.IntT2);
213 GC_push_one ((word) thread_table[i].context.IntT3);
214 GC_push_one ((word) thread_table[i].context.IntT4);
215 GC_push_one ((word) thread_table[i].context.IntT5);
216 GC_push_one ((word) thread_table[i].context.IntT6);
217 GC_push_one ((word) thread_table[i].context.IntT7);
218 GC_push_one ((word) thread_table[i].context.IntS0);
219 GC_push_one ((word) thread_table[i].context.IntS1);
220 GC_push_one ((word) thread_table[i].context.IntS2);
221 GC_push_one ((word) thread_table[i].context.IntS3);
222 GC_push_one ((word) thread_table[i].context.IntS4);
223 GC_push_one ((word) thread_table[i].context.IntS5);
224 GC_push_one ((word) thread_table[i].context.IntS6);
225 GC_push_one ((word) thread_table[i].context.IntS7);
226 GC_push_one ((word) thread_table[i].context.IntT8);
227 GC_push_one ((word) thread_table[i].context.IntT9);
228 GC_push_one ((word) thread_table[i].context.IntK0);
229 GC_push_one ((word) thread_table[i].context.IntK1);
230 GC_push_one ((word) thread_table[i].context.IntS8);
231 GC_push_all_stack((char *) thread_table[i].context.IntSp,
232 thread_table[i].stack);
233 # else
234 # ifdef PPC
235 if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack
236 || thread_table[i].context.Gpr1 < (DWORD)bottom)
237 ABORT("Thread stack pointer out of range");
238 GC_push_one ((word) thread_table[i].context.Gpr0);
239 /* Gpr1 is stack pointer */
240 /* Gpr2 is global pointer */
241 GC_push_one ((word) thread_table[i].context.Gpr3);
242 GC_push_one ((word) thread_table[i].context.Gpr4);
243 GC_push_one ((word) thread_table[i].context.Gpr5);
244 GC_push_one ((word) thread_table[i].context.Gpr6);
245 GC_push_one ((word) thread_table[i].context.Gpr7);
246 GC_push_one ((word) thread_table[i].context.Gpr8);
247 GC_push_one ((word) thread_table[i].context.Gpr9);
248 GC_push_one ((word) thread_table[i].context.Gpr10);
249 GC_push_one ((word) thread_table[i].context.Gpr11);
250 GC_push_one ((word) thread_table[i].context.Gpr12);
251 /* Gpr13 is reserved for the kernel */
252 GC_push_one ((word) thread_table[i].context.Gpr14);
253 GC_push_one ((word) thread_table[i].context.Gpr15);
254 GC_push_one ((word) thread_table[i].context.Gpr16);
255 GC_push_one ((word) thread_table[i].context.Gpr17);
256 GC_push_one ((word) thread_table[i].context.Gpr18);
257 GC_push_one ((word) thread_table[i].context.Gpr19);
258 GC_push_one ((word) thread_table[i].context.Gpr20);
259 GC_push_one ((word) thread_table[i].context.Gpr21);
260 GC_push_one ((word) thread_table[i].context.Gpr22);
261 GC_push_one ((word) thread_table[i].context.Gpr23);
262 GC_push_one ((word) thread_table[i].context.Gpr24);
263 GC_push_one ((word) thread_table[i].context.Gpr25);
264 GC_push_one ((word) thread_table[i].context.Gpr26);
265 GC_push_one ((word) thread_table[i].context.Gpr27);
266 GC_push_one ((word) thread_table[i].context.Gpr28);
267 GC_push_one ((word) thread_table[i].context.Gpr29);
268 GC_push_one ((word) thread_table[i].context.Gpr30);
269 GC_push_one ((word) thread_table[i].context.Gpr31);
270 GC_push_all_stack((char *) thread_table[i].context.Gpr1,
271 thread_table[i].stack);
272 # else
273 # ifdef ALPHA
274 if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
275 || thread_table[i].context.IntSp < (DWORD)bottom)
276 ABORT("Thread stack pointer out of range");
277 GC_push_one ((word) thread_table[i].context.IntV0);
278 GC_push_one ((word) thread_table[i].context.IntT0);
279 GC_push_one ((word) thread_table[i].context.IntT1);
280 GC_push_one ((word) thread_table[i].context.IntT2);
281 GC_push_one ((word) thread_table[i].context.IntT3);
282 GC_push_one ((word) thread_table[i].context.IntT4);
283 GC_push_one ((word) thread_table[i].context.IntT5);
284 GC_push_one ((word) thread_table[i].context.IntT6);
285 GC_push_one ((word) thread_table[i].context.IntT7);
286 GC_push_one ((word) thread_table[i].context.IntS0);
287 GC_push_one ((word) thread_table[i].context.IntS1);
288 GC_push_one ((word) thread_table[i].context.IntS2);
289 GC_push_one ((word) thread_table[i].context.IntS3);
290 GC_push_one ((word) thread_table[i].context.IntS4);
291 GC_push_one ((word) thread_table[i].context.IntS5);
292 GC_push_one ((word) thread_table[i].context.IntFp);
293 GC_push_one ((word) thread_table[i].context.IntA0);
294 GC_push_one ((word) thread_table[i].context.IntA1);
295 GC_push_one ((word) thread_table[i].context.IntA2);
296 GC_push_one ((word) thread_table[i].context.IntA3);
297 GC_push_one ((word) thread_table[i].context.IntA4);
298 GC_push_one ((word) thread_table[i].context.IntA5);
299 GC_push_one ((word) thread_table[i].context.IntT8);
300 GC_push_one ((word) thread_table[i].context.IntT9);
301 GC_push_one ((word) thread_table[i].context.IntT10);
302 GC_push_one ((word) thread_table[i].context.IntT11);
303 GC_push_one ((word) thread_table[i].context.IntT12);
304 GC_push_one ((word) thread_table[i].context.IntAt);
305 GC_push_all_stack((char *) thread_table[i].context.IntSp,
306 thread_table[i].stack);
307 # else
308 --> architecture not supported
309 # endif /* !ALPHA */
310 # endif /* !PPC */
311 # endif /* !MIPS */
312 # endif /* !SHx */
313 # endif /* !ARM32 */
314 # endif /* !I386 */
319 void GC_get_next_stack(char *start, char **lo, char **hi)
321 int i;
322 # define ADDR_LIMIT (char *)(-1L)
323 char * current_min = ADDR_LIMIT;
325 for (i = 0; i < MAX_THREADS; i++) {
326 char * s = (char *)thread_table[i].stack;
328 if (0 != s && s > start && s < current_min) {
329 current_min = s;
332 *hi = current_min;
333 if (current_min == ADDR_LIMIT) {
334 *lo = ADDR_LIMIT;
335 return;
337 *lo = GC_get_lo_stack_addr(current_min);
338 if (*lo < start) *lo = start;
341 #if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))
343 HANDLE WINAPI GC_CreateThread(
344 LPSECURITY_ATTRIBUTES lpThreadAttributes,
345 DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
346 LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
348 return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
349 lpParameter, dwCreationFlags, lpThreadId);
352 #else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
354 typedef struct {
355 HANDLE child_ready_h, parent_ready_h;
356 volatile struct thread_entry * entry;
357 LPTHREAD_START_ROUTINE start;
358 LPVOID param;
359 } thread_args;
361 DWORD WINAPI thread_start(LPVOID arg);
363 HANDLE WINAPI GC_CreateThread(
364 LPSECURITY_ATTRIBUTES lpThreadAttributes,
365 DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
366 LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
368 HANDLE thread_h = NULL;
369 HANDLE child_ready_h, parent_ready_h;
371 int i;
372 thread_args args;
374 /* allocate thread slot */
375 LOCK();
376 for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
378 if (i != MAX_THREADS) {
379 thread_table[i].in_use = TRUE;
381 UNLOCK();
383 if (i != MAX_THREADS) {
385 /* create unnamed unsignalled events */
386 if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
387 if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
389 /* set up thread arguments */
390 args.child_ready_h = child_ready_h;
391 args.parent_ready_h = parent_ready_h;
392 args.entry = &thread_table[i];
393 args.start = lpStartAddress;
394 args.param = lpParameter;
396 thread_h = CreateThread(lpThreadAttributes,
397 dwStackSize, thread_start,
398 &args,
399 dwCreationFlags & ~CREATE_SUSPENDED,
400 lpThreadId);
402 if (thread_h) {
404 /* fill in ID and handle; tell child this is done */
405 thread_table[i].id = *lpThreadId;
406 thread_table[i].handle = thread_h;
407 SetEvent (parent_ready_h);
409 /* wait for child to fill in stack and copy args */
410 WaitForSingleObject (child_ready_h, INFINITE);
412 /* suspend the child if requested */
413 if (dwCreationFlags & CREATE_SUSPENDED)
414 SuspendThread (thread_h);
416 /* let child call given function now (or when resumed) */
417 SetEvent (parent_ready_h);
419 } else {
420 CloseHandle (parent_ready_h);
425 CloseHandle (child_ready_h);
427 if (thread_h == NULL)
428 thread_table[i].in_use = FALSE;
430 } else { /* no thread slot found */
431 SetLastError (ERROR_TOO_MANY_TCBS);
434 return thread_h;
437 static DWORD WINAPI thread_start(LPVOID arg)
439 DWORD ret = 0;
440 thread_args args = *(thread_args *)arg;
442 /* wait for parent to fill in ID and handle */
443 WaitForSingleObject (args.parent_ready_h, INFINITE);
444 ResetEvent (args.parent_ready_h);
446 /* fill in stack; tell parent this is done */
447 args.entry->stack = GC_get_stack_base();
448 SetEvent (args.child_ready_h);
450 /* wait for parent to tell us to go (in case it needs to suspend us) */
451 WaitForSingleObject (args.parent_ready_h, INFINITE);
452 CloseHandle (args.parent_ready_h);
454 /* Clear the thread entry even if we exit with an exception. */
455 /* This is probably pointless, since an uncaught exception is */
456 /* supposed to result in the process being killed. */
457 #ifndef __GNUC__
458 __try {
459 #endif /* __GNUC__ */
460 ret = args.start (args.param);
461 #ifndef __GNUC__
462 } __finally {
463 #endif /* __GNUC__ */
464 LOCK();
465 args.entry->stack = 0;
466 args.entry->in_use = FALSE;
467 /* cast away volatile qualifier */
468 BZERO((void *) &args.entry->context, sizeof(CONTEXT));
469 UNLOCK();
470 #ifndef __GNUC__
472 #endif /* __GNUC__ */
474 return ret;
476 #endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
478 #ifdef MSWINCE
480 typedef struct {
481 HINSTANCE hInstance;
482 HINSTANCE hPrevInstance;
483 LPWSTR lpCmdLine;
484 int nShowCmd;
485 } main_thread_args;
487 DWORD WINAPI main_thread_start(LPVOID arg);
489 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
490 LPWSTR lpCmdLine, int nShowCmd)
492 DWORD exit_code = 1;
494 main_thread_args args = {
495 hInstance, hPrevInstance, lpCmdLine, nShowCmd
497 HANDLE thread_h;
498 DWORD thread_id;
500 /* initialize everything */
501 InitializeCriticalSection(&GC_allocate_ml);
502 GC_init();
504 /* start the main thread */
505 thread_h = GC_CreateThread(
506 NULL, 0, main_thread_start, &args, 0, &thread_id);
508 if (thread_h != NULL)
510 WaitForSingleObject (thread_h, INFINITE);
511 GetExitCodeThread (thread_h, &exit_code);
512 CloseHandle (thread_h);
515 GC_deinit();
516 DeleteCriticalSection(&GC_allocate_ml);
518 return (int) exit_code;
521 DWORD WINAPI main_thread_start(LPVOID arg)
523 main_thread_args * args = (main_thread_args *) arg;
525 return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
526 args->lpCmdLine, args->nShowCmd);
529 # else /* !MSWINCE */
531 LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
534 * This isn't generally safe, since DllMain is not premptible.
535 * If another thread holds the lock while this runs we're in trouble.
536 * Pontus Rydin suggests wrapping the thread start routine instead.
538 BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
540 switch (reason) {
541 case DLL_PROCESS_ATTACH:
542 InitializeCriticalSection(&GC_allocate_ml);
543 GC_init(); /* Force initialization before thread attach. */
544 /* fall through */
545 case DLL_THREAD_ATTACH:
547 int i;
548 /* It appears to be unsafe to acquire a lock here, since this */
549 /* code is apparently not preeemptible on some systems. */
550 /* (This is based on complaints, not on Microsoft's official */
551 /* documentation, which says this should perform "only simple */
552 /* inititalization tasks".) */
553 /* Hence we make do with nonblocking synchronization. */
555 /* The following should be a noop according to the win32 */
556 /* documentation. There is empirical evidence that it */
557 /* isn't. - HB */
558 # ifdef MPROTECT_VDB
559 if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
560 # endif
562 for (i = 0;
563 /* cast away volatile qualifier */
564 InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
565 i++) {
566 /* Compare-and-swap would make this cleaner, but that's not */
567 /* supported before Windows 98 and NT 4.0. In Windows 2000, */
568 /* InterlockedExchange is supposed to be replaced by */
569 /* InterlockedExchangePointer, but that's not really what I */
570 /* want here. */
571 if (i == MAX_THREADS - 1)
572 ABORT("too many threads");
574 thread_table[i].id = GetCurrentThreadId();
575 if (!DuplicateHandle(GetCurrentProcess(),
576 GetCurrentThread(),
577 GetCurrentProcess(),
578 /* cast away volatile qualifier */
579 (HANDLE *) &thread_table[i].handle,
582 DUPLICATE_SAME_ACCESS)) {
583 DWORD last_error = GetLastError();
584 GC_printf1("Last error code: %lx\n", last_error);
585 ABORT("DuplicateHandle failed");
587 thread_table[i].stack = GC_get_stack_base();
588 /* If this thread is being created while we are trying to stop */
589 /* the world, wait here. Hopefully this can't happen on any */
590 /* systems that don't allow us to block here. */
591 while (GC_please_stop) Sleep(20);
593 break;
594 case DLL_THREAD_DETACH:
596 int i;
597 DWORD thread_id = GetCurrentThreadId();
598 LOCK();
599 for (i = 0;
600 i < MAX_THREADS &&
601 (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
602 i++) {}
603 if (i >= MAX_THREADS) {
604 WARN("thread %ld not found on detach", (GC_word)thread_id);
605 } else {
606 thread_table[i].stack = 0;
607 thread_table[i].in_use = FALSE;
608 CloseHandle(thread_table[i].handle);
609 /* cast away volatile qualifier */
610 BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
612 UNLOCK();
614 break;
615 case DLL_PROCESS_DETACH:
617 int i;
619 LOCK();
620 for (i = 0; i < MAX_THREADS; ++i)
622 if (thread_table[i].in_use)
624 thread_table[i].stack = 0;
625 thread_table[i].in_use = FALSE;
626 CloseHandle(thread_table[i].handle);
627 BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
630 UNLOCK();
632 GC_deinit();
633 DeleteCriticalSection(&GC_allocate_ml);
635 break;
638 return TRUE;
641 # endif /* !MSWINCE */
643 #endif /* GC_WIN32_THREADS */