Move 'temporary' bits so they don't conflict with windows/cygwin/dgux bits
[official-gcc.git] / boehm-gc / win32_threads.c
blobeb485bdc064d1a4513da4023bec876288184a1f7
1 #ifdef WIN32_THREADS
3 #include "gc_priv.h"
5 #define STRICT
6 #include <windows.h>
8 #define MAX_THREADS 64
10 struct thread_entry {
11 DWORD id;
12 HANDLE handle;
13 void *stack; /* The cold end of the stack. */
14 CONTEXT context;
17 struct thread_entry thread_table[MAX_THREADS];
19 void GC_stop_world()
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");
30 void GC_start_world()
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");
41 ptr_t GC_current_stackbottom()
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");
51 ptr_t GC_get_lo_stack_addr(ptr_t s)
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);
63 void GC_push_all_stacks()
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);
86 void GC_get_next_stack(char *start, char **lo, char **hi)
88 int i;
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) {
96 current_min = s;
99 *hi = current_min;
100 if (current_min == ADDR_LIMIT) {
101 *lo = ADDR_LIMIT;
102 return;
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)
117 switch (reason) {
118 case DLL_PROCESS_ATTACH:
119 InitializeCriticalSection(&GC_allocate_ml);
120 /* fall through */
121 case DLL_THREAD_ATTACH:
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");
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,
141 DUPLICATE_SAME_ACCESS)) {
142 DWORD last_error = GetLastError();
143 GC_printf1("Last error code: %lx\n", last_error);
144 ABORT("DuplicateHandle failed");
146 UNLOCK();
148 break;
149 case DLL_PROCESS_DETACH:
150 case DLL_THREAD_DETACH:
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();
163 break;
165 return TRUE;
168 #endif /* WIN32_THREADS */