source: trunk/gcc/boehm-gc/win32_threads.c

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

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