OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.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 */