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