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