Annotation of OpenXM_contrib2/asir2000/gc/win32_threads.c, Revision 1.3
1.3 ! noro 1: #if defined(GC_WIN32_THREADS) || defined(WIN32_THREADS)
1.1 noro 2:
1.3 ! noro 3: #include "private/gc_priv.h"
1.1 noro 4:
1.2 noro 5: #if 0
1.1 noro 6: #define STRICT
7: #include <windows.h>
1.2 noro 8: #endif
1.1 noro 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:
1.3 ! noro 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:
1.1 noro 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) {
1.3 ! noro 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) &&
1.2 noro 55: exitCode != STILL_ACTIVE) {
56: thread_table[i].stack = 0;
1.3 ! noro 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
1.1 noro 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:
1.3 ! noro 83: # ifdef _MSC_VER
! 84: # pragma warning(disable:4715)
! 85: # endif
1.1 noro 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: }
1.3 ! noro 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
1.1 noro 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)
1.3 ! noro 128: GC_push_all_stack((ptr_t)&i, thread_table[i].stack);
1.1 noro 129: else {
130: thread_table[i].context.ContextFlags
131: = (CONTEXT_INTEGER|CONTEXT_CONTROL);
132: if (!GetThreadContext(thread_table[i].handle,
1.3 ! noro 133: /* cast away volatile qualifier */
! 134: (LPCONTEXT)&thread_table[i].context))
1.1 noro 135: ABORT("GetThreadContext failed");
1.3 ! noro 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 */
1.1 noro 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:
1.3 ! noro 334:
! 335: # ifdef MSWINCE
! 336:
! 337: typedef struct {
! 338: HANDLE child_ready_h, parent_ready_h;
! 339: volatile struct thread_entry * entry;
! 340: LPTHREAD_START_ROUTINE start;
! 341: LPVOID param;
! 342: } thread_args;
! 343:
! 344: DWORD WINAPI thread_start(LPVOID arg);
! 345:
! 346: HANDLE WINAPI GC_CreateThread(
! 347: LPSECURITY_ATTRIBUTES lpThreadAttributes,
! 348: DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
! 349: LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
! 350: {
! 351: HANDLE thread_h = NULL;
! 352: HANDLE child_ready_h, parent_ready_h;
! 353:
! 354: int i;
! 355: thread_args args;
! 356:
! 357: /* allocate thread slot */
! 358: LOCK();
! 359: for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
! 360: ;
! 361: if (i != MAX_THREADS) {
! 362: thread_table[i].in_use = TRUE;
! 363: }
! 364: UNLOCK();
! 365:
! 366: if (i != MAX_THREADS) {
! 367:
! 368: /* create unnamed unsignalled events */
! 369: if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
! 370: if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
! 371:
! 372: /* set up thread arguments */
! 373: args.child_ready_h = child_ready_h;
! 374: args.parent_ready_h = parent_ready_h;
! 375: args.entry = &thread_table[i];
! 376: args.start = lpStartAddress;
! 377: args.param = lpParameter;
! 378:
! 379: thread_h = CreateThread(lpThreadAttributes,
! 380: dwStackSize, thread_start,
! 381: &args,
! 382: dwCreationFlags & ~CREATE_SUSPENDED,
! 383: lpThreadId);
! 384:
! 385: if (thread_h) {
! 386:
! 387: /* fill in ID and handle; tell child this is done */
! 388: thread_table[i].id = *lpThreadId;
! 389: thread_table[i].handle = thread_h;
! 390: SetEvent (parent_ready_h);
! 391:
! 392: /* wait for child to fill in stack and copy args */
! 393: WaitForSingleObject (child_ready_h, INFINITE);
! 394:
! 395: /* suspend the child if requested */
! 396: if (dwCreationFlags & CREATE_SUSPENDED)
! 397: SuspendThread (thread_h);
! 398:
! 399: /* let child call given function now (or when resumed) */
! 400: SetEvent (parent_ready_h);
! 401:
! 402: } else {
! 403: CloseHandle (parent_ready_h);
! 404: }
! 405: }
! 406: }
! 407:
! 408: CloseHandle (child_ready_h);
! 409:
! 410: if (thread_h == NULL)
! 411: thread_table[i].in_use = FALSE;
! 412:
! 413: } else { /* no thread slot found */
! 414: SetLastError (ERROR_TOO_MANY_TCBS);
! 415: }
! 416:
! 417: return thread_h;
! 418: }
! 419:
! 420: static DWORD WINAPI thread_start(LPVOID arg)
! 421: {
! 422: DWORD ret = 0;
! 423: thread_args args = *(thread_args *)arg;
! 424:
! 425: /* wait for parent to fill in ID and handle */
! 426: WaitForSingleObject (args.parent_ready_h, INFINITE);
! 427: ResetEvent (args.parent_ready_h);
! 428:
! 429: /* fill in stack; tell parent this is done */
! 430: args.entry->stack = GC_get_stack_base();
! 431: SetEvent (args.child_ready_h);
! 432:
! 433: /* wait for parent to tell us to go (in case it needs to suspend us) */
! 434: WaitForSingleObject (args.parent_ready_h, INFINITE);
! 435: CloseHandle (args.parent_ready_h);
! 436:
! 437: /* Clear the thread entry even if we exit with an exception. */
! 438: /* This is probably pointless, since an uncaught exception is */
! 439: /* supposed to result in the process being killed. */
! 440: __try {
! 441: ret = args.start (args.param);
! 442: } __finally {
! 443: LOCK();
! 444: args.entry->stack = 0;
! 445: args.entry->in_use = FALSE;
! 446: /* cast away volatile qualifier */
! 447: BZERO((void *) &args.entry->context, sizeof(CONTEXT));
! 448: UNLOCK();
! 449: }
! 450:
! 451: return ret;
! 452: }
! 453:
! 454: typedef struct {
! 455: HINSTANCE hInstance;
! 456: HINSTANCE hPrevInstance;
! 457: LPWSTR lpCmdLine;
! 458: int nShowCmd;
! 459: } main_thread_args;
! 460:
! 461: DWORD WINAPI main_thread_start(LPVOID arg);
! 462:
! 463: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
! 464: LPWSTR lpCmdLine, int nShowCmd)
! 465: {
! 466: DWORD exit_code = 1;
! 467:
! 468: main_thread_args args = {
! 469: hInstance, hPrevInstance, lpCmdLine, nShowCmd
! 470: };
! 471: HANDLE thread_h;
! 472: DWORD thread_id;
! 473:
! 474: /* initialize everything */
! 475: InitializeCriticalSection(&GC_allocate_ml);
! 476: GC_init();
! 477:
! 478: /* start the main thread */
! 479: thread_h = GC_CreateThread(
! 480: NULL, 0, main_thread_start, &args, 0, &thread_id);
! 481:
! 482: if (thread_h != NULL)
! 483: {
! 484: WaitForSingleObject (thread_h, INFINITE);
! 485: GetExitCodeThread (thread_h, &exit_code);
! 486: CloseHandle (thread_h);
! 487: }
! 488:
! 489: GC_deinit();
! 490: DeleteCriticalSection(&GC_allocate_ml);
! 491:
! 492: return (int) exit_code;
! 493: }
! 494:
! 495: DWORD WINAPI main_thread_start(LPVOID arg)
! 496: {
! 497: main_thread_args * args = (main_thread_args *) arg;
! 498:
! 499: return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
! 500: args->lpCmdLine, args->nShowCmd);
! 501: }
! 502:
! 503: # else /* !MSWINCE */
! 504:
1.1 noro 505: LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
506:
507: /*
508: * This isn't generally safe, since DllMain is not premptible.
509: * If another thread holds the lock while this runs we're in trouble.
510: * Pontus Rydin suggests wrapping the thread start routine instead.
511: */
512: BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
513: {
514: switch (reason) {
515: case DLL_PROCESS_ATTACH:
516: InitializeCriticalSection(&GC_allocate_ml);
517: GC_init(); /* Force initialization before thread attach. */
518: /* fall through */
519: case DLL_THREAD_ATTACH:
520: {
521: int i;
522: /* It appears to be unsafe to acquire a lock here, since this */
523: /* code is apparently not preeemptible on some systems. */
524: /* (This is based on complaints, not on Microsoft's official */
525: /* documentation, which says this should perform "only simple */
526: /* inititalization tasks".) */
527: /* Hence we make do with nonblocking synchronization. */
528:
529: /* The following should be a noop according to the win32 */
530: /* documentation. There is empirical evidence that it */
531: /* isn't. - HB */
1.3 ! noro 532: # ifdef MPROTECT_VDB
1.1 noro 533: if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
534: # endif
535:
1.3 ! noro 536: for (i = 0;
! 537: /* cast away volatile qualifier */
! 538: InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
! 539: i++) {
1.1 noro 540: /* Compare-and-swap would make this cleaner, but that's not */
541: /* supported before Windows 98 and NT 4.0. In Windows 2000, */
542: /* InterlockedExchange is supposed to be replaced by */
543: /* InterlockedExchangePointer, but that's not really what I */
544: /* want here. */
545: if (i == MAX_THREADS - 1)
546: ABORT("too many threads");
547: }
548: thread_table[i].id = GetCurrentThreadId();
549: if (!DuplicateHandle(GetCurrentProcess(),
1.3 ! noro 550: GetCurrentThread(),
1.1 noro 551: GetCurrentProcess(),
1.3 ! noro 552: /* cast away volatile qualifier */
! 553: (HANDLE *) &thread_table[i].handle,
1.1 noro 554: 0,
555: 0,
556: DUPLICATE_SAME_ACCESS)) {
1.3 ! noro 557: DWORD last_error = GetLastError();
! 558: GC_printf1("Last error code: %lx\n", last_error);
! 559: ABORT("DuplicateHandle failed");
1.1 noro 560: }
561: thread_table[i].stack = GC_get_stack_base();
562: /* If this thread is being created while we are trying to stop */
563: /* the world, wait here. Hopefully this can't happen on any */
564: /* systems that don't allow us to block here. */
565: while (GC_please_stop) Sleep(20);
566: }
567: break;
568: case DLL_THREAD_DETACH:
569: {
570: int i;
571: DWORD thread_id = GetCurrentThreadId();
572: LOCK();
573: for (i = 0;
1.3 ! noro 574: i < MAX_THREADS &&
! 575: (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
! 576: i++) {}
! 577: if (i >= MAX_THREADS) {
! 578: WARN("thread %ld not found on detach", (GC_word)thread_id);
! 579: } else {
! 580: thread_table[i].stack = 0;
! 581: thread_table[i].in_use = FALSE;
! 582: CloseHandle(thread_table[i].handle);
! 583: /* cast away volatile qualifier */
! 584: BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
! 585: }
! 586: UNLOCK();
! 587: }
! 588: break;
! 589: case DLL_PROCESS_DETACH:
! 590: {
! 591: int i;
! 592:
! 593: LOCK();
! 594: for (i = 0; i < MAX_THREADS; ++i)
! 595: {
! 596: if (thread_table[i].in_use)
! 597: {
! 598: thread_table[i].stack = 0;
! 599: thread_table[i].in_use = FALSE;
! 600: CloseHandle(thread_table[i].handle);
! 601: BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
! 602: }
1.1 noro 603: }
604: UNLOCK();
1.3 ! noro 605:
! 606: GC_deinit();
! 607: DeleteCriticalSection(&GC_allocate_ml);
1.1 noro 608: }
609: break;
1.3 ! noro 610:
1.1 noro 611: }
612: return TRUE;
613: }
1.3 ! noro 614:
! 615: # endif /* !MSWINCE */
1.1 noro 616:
617: #endif /* WIN32_THREADS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>