13 void *stack; /* The cold end of the stack. */
17 struct thread_entry thread_table[MAX_THREADS];
21 DWORD thread_id = GetCurrentThreadId();
23 for (i = 0; i < MAX_THREADS; i++)
24 if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) {
25 if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
26 ABORT("SuspendThread failed");
32 DWORD thread_id = GetCurrentThreadId();
34 for (i = 0; i < MAX_THREADS; i++)
35 if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) {
36 if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
37 ABORT("ResumeThread failed");
41 ptr_t GC_current_stackbottom()
43 DWORD thread_id = GetCurrentThreadId();
45 for (i = 0; i < MAX_THREADS; i++)
46 if (thread_table[i].stack && thread_table[i].id == thread_id)
47 return thread_table[i].stack;
48 ABORT("no thread table entry for current thread");
51 ptr_t GC_get_lo_stack_addr(ptr_t s)
54 MEMORY_BASIC_INFORMATION info;
55 VirtualQuery(s, &info, sizeof(info));
57 bottom = info.BaseAddress;
58 VirtualQuery(bottom - 1, &info, sizeof(info));
59 } while ((info.Protect & PAGE_READWRITE) && !(info.Protect & PAGE_GUARD));
63 void GC_push_all_stacks()
65 DWORD thread_id = GetCurrentThreadId();
67 for (i = 0; i < MAX_THREADS; i++)
68 if (thread_table[i].stack) {
69 ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);
70 if (thread_table[i].id == thread_id)
71 GC_push_all(&i, thread_table[i].stack);
73 thread_table[i].context.ContextFlags
74 = (CONTEXT_INTEGER|CONTEXT_CONTROL);
75 if (!GetThreadContext(thread_table[i].handle,
76 &thread_table[i].context))
77 ABORT("GetThreadContext failed");
78 if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
79 || thread_table[i].context.Esp < (DWORD)bottom)
80 ABORT("Thread stack pointer out of range");
81 GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack);
86 void GC_get_next_stack(char *start, char **lo, char **hi)
89 # define ADDR_LIMIT (char *)(-1L)
90 char * current_min = ADDR_LIMIT;
92 for (i = 0; i < MAX_THREADS; i++) {
93 char * s = (char *)thread_table[i].stack;
95 if (0 != s && s > start && s < current_min) {
100 if (current_min == ADDR_LIMIT) {
104 *lo = GC_get_lo_stack_addr(current_min);
105 if (*lo < start) *lo = start;
108 LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
111 * This isn't generally safe, since DllMain is not premptible.
112 * If another thread holds the lock while this runs we're in trouble.
113 * Pontus Rydin suggests wrapping the thread start routine instead.
115 BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
118 case DLL_PROCESS_ATTACH:
119 InitializeCriticalSection(&GC_allocate_ml);
121 case DLL_THREAD_ATTACH:
125 /* The following should be a noop according to the win32 */
126 /* documentation. There is empirical evidence that it */
128 if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
129 for (i = 0; thread_table[i].stack != 0; i++) {
130 if (i == MAX_THREADS - 1)
131 ABORT("too many threads");
133 thread_table[i].stack = GC_get_stack_base();
134 thread_table[i].id = GetCurrentThreadId();
135 if (!DuplicateHandle(GetCurrentProcess(),
138 &thread_table[i].handle,
141 DUPLICATE_SAME_ACCESS)) {
142 DWORD last_error = GetLastError();
143 GC_printf1("Last error code: %lx\n", last_error);
144 ABORT("DuplicateHandle failed");
149 case DLL_PROCESS_DETACH:
150 case DLL_THREAD_DETACH:
153 DWORD thread_id = GetCurrentThreadId();
155 for (i = 0; thread_table[i].stack == 0 || thread_table[i].id != thread_id; i++)
156 if (i == MAX_THREADS - 1)
157 ABORT("thread not found on detach");
158 thread_table[i].stack = 0;
159 CloseHandle(thread_table[i].handle);
160 BZERO(&thread_table[i].context, sizeof(CONTEXT));
168 #endif /* WIN32_THREADS */