]> git.ipfire.org Git - thirdparty/gcc.git/blob - boehm-gc/win32_threads.c
Initial revision
[thirdparty/gcc.git] / boehm-gc / win32_threads.c
1 #ifdef WIN32_THREADS
2
3 #include "gc_priv.h"
4
5 #define STRICT
6 #include <windows.h>
7
8 #define MAX_THREADS 64
9
10 struct thread_entry {
11 DWORD id;
12 HANDLE handle;
13 void *stack; /* The cold end of the stack. */
14 CONTEXT context;
15 };
16
17 struct thread_entry thread_table[MAX_THREADS];
18
19 void GC_stop_world()
20 {
21 DWORD thread_id = GetCurrentThreadId();
22 int i;
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");
27 }
28 }
29
30 void GC_start_world()
31 {
32 DWORD thread_id = GetCurrentThreadId();
33 int i;
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");
38 }
39 }
40
41 ptr_t GC_current_stackbottom()
42 {
43 DWORD thread_id = GetCurrentThreadId();
44 int i;
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");
49 }
50
51 ptr_t GC_get_lo_stack_addr(ptr_t s)
52 {
53 ptr_t bottom;
54 MEMORY_BASIC_INFORMATION info;
55 VirtualQuery(s, &info, sizeof(info));
56 do {
57 bottom = info.BaseAddress;
58 VirtualQuery(bottom - 1, &info, sizeof(info));
59 } while ((info.Protect & PAGE_READWRITE) && !(info.Protect & PAGE_GUARD));
60 return(bottom);
61 }
62
63 void GC_push_all_stacks()
64 {
65 DWORD thread_id = GetCurrentThreadId();
66 int i;
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);
72 else {
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);
82 }
83 }
84 }
85
86 void GC_get_next_stack(char *start, char **lo, char **hi)
87 {
88 int i;
89 # define ADDR_LIMIT (char *)(-1L)
90 char * current_min = ADDR_LIMIT;
91
92 for (i = 0; i < MAX_THREADS; i++) {
93 char * s = (char *)thread_table[i].stack;
94
95 if (0 != s && s > start && s < current_min) {
96 current_min = s;
97 }
98 }
99 *hi = current_min;
100 if (current_min == ADDR_LIMIT) {
101 *lo = ADDR_LIMIT;
102 return;
103 }
104 *lo = GC_get_lo_stack_addr(current_min);
105 if (*lo < start) *lo = start;
106 }
107
108 LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
109
110 /*
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.
114 */
115 BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
116 {
117 switch (reason) {
118 case DLL_PROCESS_ATTACH:
119 InitializeCriticalSection(&GC_allocate_ml);
120 /* fall through */
121 case DLL_THREAD_ATTACH:
122 {
123 int i;
124 LOCK();
125 /* The following should be a noop according to the win32 */
126 /* documentation. There is empirical evidence that it */
127 /* isn't. - HB */
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");
132 }
133 thread_table[i].stack = GC_get_stack_base();
134 thread_table[i].id = GetCurrentThreadId();
135 if (!DuplicateHandle(GetCurrentProcess(),
136 GetCurrentThread(),
137 GetCurrentProcess(),
138 &thread_table[i].handle,
139 0,
140 0,
141 DUPLICATE_SAME_ACCESS)) {
142 DWORD last_error = GetLastError();
143 GC_printf1("Last error code: %lx\n", last_error);
144 ABORT("DuplicateHandle failed");
145 }
146 UNLOCK();
147 }
148 break;
149 case DLL_PROCESS_DETACH:
150 case DLL_THREAD_DETACH:
151 {
152 int i;
153 DWORD thread_id = GetCurrentThreadId();
154 LOCK();
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));
161 UNLOCK();
162 }
163 break;
164 }
165 return TRUE;
166 }
167
168 #endif /* WIN32_THREADS */