| 1 | #if defined(GC_WIN32_THREADS) | 
|---|
| 2 |  | 
|---|
| 3 | #include "private/gc_priv.h" | 
|---|
| 4 |  | 
|---|
| 5 | #if 0 | 
|---|
| 6 | #define STRICT | 
|---|
| 7 | #include <windows.h> | 
|---|
| 8 | #endif | 
|---|
| 9 |  | 
|---|
| 10 | #define MAX_THREADS 64 | 
|---|
| 11 |  | 
|---|
| 12 | struct thread_entry { | 
|---|
| 13 | LONG in_use; | 
|---|
| 14 | DWORD id; | 
|---|
| 15 | HANDLE handle; | 
|---|
| 16 | void *stack;          /* The cold end of the stack.   */ | 
|---|
| 17 | /* 0 ==> entry not valid.       */ | 
|---|
| 18 | /* !in_use ==> stack == 0       */ | 
|---|
| 19 | CONTEXT context; | 
|---|
| 20 | GC_bool suspended; | 
|---|
| 21 | }; | 
|---|
| 22 |  | 
|---|
| 23 | volatile GC_bool GC_please_stop = FALSE; | 
|---|
| 24 |  | 
|---|
| 25 | volatile struct thread_entry thread_table[MAX_THREADS]; | 
|---|
| 26 |  | 
|---|
| 27 | void GC_push_thread_structures GC_PROTO((void)) | 
|---|
| 28 | { | 
|---|
| 29 | /* Unlike the other threads implementations, the thread table here  */ | 
|---|
| 30 | /* contains no pointers to the collectable heap.  Thus we have      */ | 
|---|
| 31 | /* no private structures we need to preserve.                       */ | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | void GC_stop_world() | 
|---|
| 35 | { | 
|---|
| 36 | DWORD thread_id = GetCurrentThreadId(); | 
|---|
| 37 | int i; | 
|---|
| 38 |  | 
|---|
| 39 | GC_please_stop = TRUE; | 
|---|
| 40 | for (i = 0; i < MAX_THREADS; i++) | 
|---|
| 41 | if (thread_table[i].stack != 0 | 
|---|
| 42 | && thread_table[i].id != thread_id) { | 
|---|
| 43 | #     ifdef MSWINCE | 
|---|
| 44 | /* SuspendThread will fail if thread is running kernel code */ | 
|---|
| 45 | while (SuspendThread(thread_table[i].handle) == (DWORD)-1) | 
|---|
| 46 | Sleep(10); | 
|---|
| 47 | #     else | 
|---|
| 48 | /* Apparently the Windows 95 GetOpenFileName call creates       */ | 
|---|
| 49 | /* a thread that does not properly get cleaned up, and          */ | 
|---|
| 50 | /* SuspendThread on its descriptor may provoke a crash.         */ | 
|---|
| 51 | /* This reduces the probability of that event, though it still  */ | 
|---|
| 52 | /* appears there's a race here.                                 */ | 
|---|
| 53 | DWORD exitCode; | 
|---|
| 54 | if (GetExitCodeThread(thread_table[i].handle,&exitCode) && | 
|---|
| 55 | exitCode != STILL_ACTIVE) { | 
|---|
| 56 | thread_table[i].stack = 0; | 
|---|
| 57 | thread_table[i].in_use = FALSE; | 
|---|
| 58 | CloseHandle(thread_table[i].handle); | 
|---|
| 59 | BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT)); | 
|---|
| 60 | continue; | 
|---|
| 61 | } | 
|---|
| 62 | if (SuspendThread(thread_table[i].handle) == (DWORD)-1) | 
|---|
| 63 | ABORT("SuspendThread failed"); | 
|---|
| 64 | #     endif | 
|---|
| 65 | thread_table[i].suspended = TRUE; | 
|---|
| 66 | } | 
|---|
| 67 | } | 
|---|
| 68 |  | 
|---|
| 69 | void GC_start_world() | 
|---|
| 70 | { | 
|---|
| 71 | DWORD thread_id = GetCurrentThreadId(); | 
|---|
| 72 | int i; | 
|---|
| 73 | for (i = 0; i < MAX_THREADS; i++) | 
|---|
| 74 | if (thread_table[i].stack != 0 && thread_table[i].suspended | 
|---|
| 75 | && thread_table[i].id != thread_id) { | 
|---|
| 76 | if (ResumeThread(thread_table[i].handle) == (DWORD)-1) | 
|---|
| 77 | ABORT("ResumeThread failed"); | 
|---|
| 78 | thread_table[i].suspended = FALSE; | 
|---|
| 79 | } | 
|---|
| 80 | GC_please_stop = FALSE; | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | # ifdef _MSC_VER | 
|---|
| 84 | #   pragma warning(disable:4715) | 
|---|
| 85 | # endif | 
|---|
| 86 | ptr_t GC_current_stackbottom() | 
|---|
| 87 | { | 
|---|
| 88 | DWORD thread_id = GetCurrentThreadId(); | 
|---|
| 89 | int i; | 
|---|
| 90 | for (i = 0; i < MAX_THREADS; i++) | 
|---|
| 91 | if (thread_table[i].stack && thread_table[i].id == thread_id) | 
|---|
| 92 | return thread_table[i].stack; | 
|---|
| 93 | ABORT("no thread table entry for current thread"); | 
|---|
| 94 | } | 
|---|
| 95 | # ifdef _MSC_VER | 
|---|
| 96 | #   pragma warning(default:4715) | 
|---|
| 97 | # endif | 
|---|
| 98 |  | 
|---|
| 99 | # ifdef MSWINCE | 
|---|
| 100 | /* The VirtualQuery calls below won't work properly on WinCE, but   */ | 
|---|
| 101 | /* since each stack is restricted to an aligned 64K region of       */ | 
|---|
| 102 | /* virtual memory we can just take the next lowest multiple of 64K. */ | 
|---|
| 103 | #   define GC_get_lo_stack_addr(s) \ | 
|---|
| 104 | ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000)) | 
|---|
| 105 | # else | 
|---|
| 106 | static ptr_t GC_get_lo_stack_addr(ptr_t s) | 
|---|
| 107 | { | 
|---|
| 108 | ptr_t bottom; | 
|---|
| 109 | MEMORY_BASIC_INFORMATION info; | 
|---|
| 110 | VirtualQuery(s, &info, sizeof(info)); | 
|---|
| 111 | do { | 
|---|
| 112 | bottom = info.BaseAddress; | 
|---|
| 113 | VirtualQuery(bottom - 1, &info, sizeof(info)); | 
|---|
| 114 | } while ((info.Protect & PAGE_READWRITE) | 
|---|
| 115 | && !(info.Protect & PAGE_GUARD)); | 
|---|
| 116 | return(bottom); | 
|---|
| 117 | } | 
|---|
| 118 | # endif | 
|---|
| 119 |  | 
|---|
| 120 | void GC_push_all_stacks() | 
|---|
| 121 | { | 
|---|
| 122 | DWORD thread_id = GetCurrentThreadId(); | 
|---|
| 123 | int i; | 
|---|
| 124 | for (i = 0; i < MAX_THREADS; i++) | 
|---|
| 125 | if (thread_table[i].stack) { | 
|---|
| 126 | ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack); | 
|---|
| 127 | if (thread_table[i].id == thread_id) | 
|---|
| 128 | GC_push_all_stack((ptr_t)&i, thread_table[i].stack); | 
|---|
| 129 | else { | 
|---|
| 130 | thread_table[i].context.ContextFlags | 
|---|
| 131 | = (CONTEXT_INTEGER|CONTEXT_CONTROL); | 
|---|
| 132 | if (!GetThreadContext(thread_table[i].handle, | 
|---|
| 133 | /* cast away volatile qualifier */ | 
|---|
| 134 | (LPCONTEXT)&thread_table[i].context)) | 
|---|
| 135 | ABORT("GetThreadContext failed"); | 
|---|
| 136 | #       ifdef I386 | 
|---|
| 137 | GC_push_one ((word) thread_table[i].context.Edi); | 
|---|
| 138 | GC_push_one ((word) thread_table[i].context.Esi); | 
|---|
| 139 | GC_push_one ((word) thread_table[i].context.Ebp); | 
|---|
| 140 | GC_push_one ((word) thread_table[i].context.Ebx); | 
|---|
| 141 | GC_push_one ((word) thread_table[i].context.Edx); | 
|---|
| 142 | GC_push_one ((word) thread_table[i].context.Ecx); | 
|---|
| 143 | GC_push_one ((word) thread_table[i].context.Eax); | 
|---|
| 144 | if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack | 
|---|
| 145 | || thread_table[i].context.Esp < (DWORD)bottom) { | 
|---|
| 146 | WARN("Thread stack pointer 0x%lx out of range, pushing everything", | 
|---|
| 147 | thread_table[i].context.Esp); | 
|---|
| 148 | GC_push_all_stack((char *) bottom, thread_table[i].stack); | 
|---|
| 149 | } else { | 
|---|
| 150 | GC_push_all_stack((char *) thread_table[i].context.Esp, | 
|---|
| 151 | thread_table[i].stack); | 
|---|
| 152 | } | 
|---|
| 153 | #       else | 
|---|
| 154 | #       ifdef ARM32 | 
|---|
| 155 | if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack | 
|---|
| 156 | || thread_table[i].context.Sp < (DWORD)bottom) | 
|---|
| 157 | ABORT("Thread stack pointer out of range"); | 
|---|
| 158 | GC_push_one ((word) thread_table[i].context.R0); | 
|---|
| 159 | GC_push_one ((word) thread_table[i].context.R1); | 
|---|
| 160 | GC_push_one ((word) thread_table[i].context.R2); | 
|---|
| 161 | GC_push_one ((word) thread_table[i].context.R3); | 
|---|
| 162 | GC_push_one ((word) thread_table[i].context.R4); | 
|---|
| 163 | GC_push_one ((word) thread_table[i].context.R5); | 
|---|
| 164 | GC_push_one ((word) thread_table[i].context.R6); | 
|---|
| 165 | GC_push_one ((word) thread_table[i].context.R7); | 
|---|
| 166 | GC_push_one ((word) thread_table[i].context.R8); | 
|---|
| 167 | GC_push_one ((word) thread_table[i].context.R9); | 
|---|
| 168 | GC_push_one ((word) thread_table[i].context.R10); | 
|---|
| 169 | GC_push_one ((word) thread_table[i].context.R11); | 
|---|
| 170 | GC_push_one ((word) thread_table[i].context.R12); | 
|---|
| 171 | GC_push_all_stack((char *) thread_table[i].context.Sp, | 
|---|
| 172 | thread_table[i].stack); | 
|---|
| 173 | #       else | 
|---|
| 174 | #       ifdef SHx | 
|---|
| 175 | if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack | 
|---|
| 176 | || thread_table[i].context.R15 < (DWORD)bottom) | 
|---|
| 177 | ABORT("Thread stack pointer out of range"); | 
|---|
| 178 | GC_push_one ((word) thread_table[i].context.R0); | 
|---|
| 179 | GC_push_one ((word) thread_table[i].context.R1); | 
|---|
| 180 | GC_push_one ((word) thread_table[i].context.R2); | 
|---|
| 181 | GC_push_one ((word) thread_table[i].context.R3); | 
|---|
| 182 | GC_push_one ((word) thread_table[i].context.R4); | 
|---|
| 183 | GC_push_one ((word) thread_table[i].context.R5); | 
|---|
| 184 | GC_push_one ((word) thread_table[i].context.R6); | 
|---|
| 185 | GC_push_one ((word) thread_table[i].context.R7); | 
|---|
| 186 | GC_push_one ((word) thread_table[i].context.R8); | 
|---|
| 187 | GC_push_one ((word) thread_table[i].context.R9); | 
|---|
| 188 | GC_push_one ((word) thread_table[i].context.R10); | 
|---|
| 189 | GC_push_one ((word) thread_table[i].context.R11); | 
|---|
| 190 | GC_push_one ((word) thread_table[i].context.R12); | 
|---|
| 191 | GC_push_one ((word) thread_table[i].context.R13); | 
|---|
| 192 | GC_push_one ((word) thread_table[i].context.R14); | 
|---|
| 193 | GC_push_all_stack((char *) thread_table[i].context.R15, | 
|---|
| 194 | thread_table[i].stack); | 
|---|
| 195 | #       else | 
|---|
| 196 | #       ifdef MIPS | 
|---|
| 197 | if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack | 
|---|
| 198 | || thread_table[i].context.IntSp < (DWORD)bottom) | 
|---|
| 199 | ABORT("Thread stack pointer out of range"); | 
|---|
| 200 | GC_push_one ((word) thread_table[i].context.IntAt); | 
|---|
| 201 | GC_push_one ((word) thread_table[i].context.IntV0); | 
|---|
| 202 | GC_push_one ((word) thread_table[i].context.IntV1); | 
|---|
| 203 | GC_push_one ((word) thread_table[i].context.IntA0); | 
|---|
| 204 | GC_push_one ((word) thread_table[i].context.IntA1); | 
|---|
| 205 | GC_push_one ((word) thread_table[i].context.IntA2); | 
|---|
| 206 | GC_push_one ((word) thread_table[i].context.IntA3); | 
|---|
| 207 | GC_push_one ((word) thread_table[i].context.IntT0); | 
|---|
| 208 | GC_push_one ((word) thread_table[i].context.IntT1); | 
|---|
| 209 | GC_push_one ((word) thread_table[i].context.IntT2); | 
|---|
| 210 | GC_push_one ((word) thread_table[i].context.IntT3); | 
|---|
| 211 | GC_push_one ((word) thread_table[i].context.IntT4); | 
|---|
| 212 | GC_push_one ((word) thread_table[i].context.IntT5); | 
|---|
| 213 | GC_push_one ((word) thread_table[i].context.IntT6); | 
|---|
| 214 | GC_push_one ((word) thread_table[i].context.IntT7); | 
|---|
| 215 | GC_push_one ((word) thread_table[i].context.IntS0); | 
|---|
| 216 | GC_push_one ((word) thread_table[i].context.IntS1); | 
|---|
| 217 | GC_push_one ((word) thread_table[i].context.IntS2); | 
|---|
| 218 | GC_push_one ((word) thread_table[i].context.IntS3); | 
|---|
| 219 | GC_push_one ((word) thread_table[i].context.IntS4); | 
|---|
| 220 | GC_push_one ((word) thread_table[i].context.IntS5); | 
|---|
| 221 | GC_push_one ((word) thread_table[i].context.IntS6); | 
|---|
| 222 | GC_push_one ((word) thread_table[i].context.IntS7); | 
|---|
| 223 | GC_push_one ((word) thread_table[i].context.IntT8); | 
|---|
| 224 | GC_push_one ((word) thread_table[i].context.IntT9); | 
|---|
| 225 | GC_push_one ((word) thread_table[i].context.IntK0); | 
|---|
| 226 | GC_push_one ((word) thread_table[i].context.IntK1); | 
|---|
| 227 | GC_push_one ((word) thread_table[i].context.IntS8); | 
|---|
| 228 | GC_push_all_stack((char *) thread_table[i].context.IntSp, | 
|---|
| 229 | thread_table[i].stack); | 
|---|
| 230 | #       else | 
|---|
| 231 | #       ifdef PPC | 
|---|
| 232 | if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack | 
|---|
| 233 | || thread_table[i].context.Gpr1 < (DWORD)bottom) | 
|---|
| 234 | ABORT("Thread stack pointer out of range"); | 
|---|
| 235 | GC_push_one ((word) thread_table[i].context.Gpr0); | 
|---|
| 236 | /* Gpr1 is stack pointer */ | 
|---|
| 237 | /* Gpr2 is global pointer */ | 
|---|
| 238 | GC_push_one ((word) thread_table[i].context.Gpr3); | 
|---|
| 239 | GC_push_one ((word) thread_table[i].context.Gpr4); | 
|---|
| 240 | GC_push_one ((word) thread_table[i].context.Gpr5); | 
|---|
| 241 | GC_push_one ((word) thread_table[i].context.Gpr6); | 
|---|
| 242 | GC_push_one ((word) thread_table[i].context.Gpr7); | 
|---|
| 243 | GC_push_one ((word) thread_table[i].context.Gpr8); | 
|---|
| 244 | GC_push_one ((word) thread_table[i].context.Gpr9); | 
|---|
| 245 | GC_push_one ((word) thread_table[i].context.Gpr10); | 
|---|
| 246 | GC_push_one ((word) thread_table[i].context.Gpr11); | 
|---|
| 247 | GC_push_one ((word) thread_table[i].context.Gpr12); | 
|---|
| 248 | /* Gpr13 is reserved for the kernel */ | 
|---|
| 249 | GC_push_one ((word) thread_table[i].context.Gpr14); | 
|---|
| 250 | GC_push_one ((word) thread_table[i].context.Gpr15); | 
|---|
| 251 | GC_push_one ((word) thread_table[i].context.Gpr16); | 
|---|
| 252 | GC_push_one ((word) thread_table[i].context.Gpr17); | 
|---|
| 253 | GC_push_one ((word) thread_table[i].context.Gpr18); | 
|---|
| 254 | GC_push_one ((word) thread_table[i].context.Gpr19); | 
|---|
| 255 | GC_push_one ((word) thread_table[i].context.Gpr20); | 
|---|
| 256 | GC_push_one ((word) thread_table[i].context.Gpr21); | 
|---|
| 257 | GC_push_one ((word) thread_table[i].context.Gpr22); | 
|---|
| 258 | GC_push_one ((word) thread_table[i].context.Gpr23); | 
|---|
| 259 | GC_push_one ((word) thread_table[i].context.Gpr24); | 
|---|
| 260 | GC_push_one ((word) thread_table[i].context.Gpr25); | 
|---|
| 261 | GC_push_one ((word) thread_table[i].context.Gpr26); | 
|---|
| 262 | GC_push_one ((word) thread_table[i].context.Gpr27); | 
|---|
| 263 | GC_push_one ((word) thread_table[i].context.Gpr28); | 
|---|
| 264 | GC_push_one ((word) thread_table[i].context.Gpr29); | 
|---|
| 265 | GC_push_one ((word) thread_table[i].context.Gpr30); | 
|---|
| 266 | GC_push_one ((word) thread_table[i].context.Gpr31); | 
|---|
| 267 | GC_push_all_stack((char *) thread_table[i].context.Gpr1, | 
|---|
| 268 | thread_table[i].stack); | 
|---|
| 269 | #       else | 
|---|
| 270 | #       ifdef ALPHA | 
|---|
| 271 | if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack | 
|---|
| 272 | || thread_table[i].context.IntSp < (DWORD)bottom) | 
|---|
| 273 | ABORT("Thread stack pointer out of range"); | 
|---|
| 274 | GC_push_one ((word) thread_table[i].context.IntV0); | 
|---|
| 275 | GC_push_one ((word) thread_table[i].context.IntT0); | 
|---|
| 276 | GC_push_one ((word) thread_table[i].context.IntT1); | 
|---|
| 277 | GC_push_one ((word) thread_table[i].context.IntT2); | 
|---|
| 278 | GC_push_one ((word) thread_table[i].context.IntT3); | 
|---|
| 279 | GC_push_one ((word) thread_table[i].context.IntT4); | 
|---|
| 280 | GC_push_one ((word) thread_table[i].context.IntT5); | 
|---|
| 281 | GC_push_one ((word) thread_table[i].context.IntT6); | 
|---|
| 282 | GC_push_one ((word) thread_table[i].context.IntT7); | 
|---|
| 283 | GC_push_one ((word) thread_table[i].context.IntS0); | 
|---|
| 284 | GC_push_one ((word) thread_table[i].context.IntS1); | 
|---|
| 285 | GC_push_one ((word) thread_table[i].context.IntS2); | 
|---|
| 286 | GC_push_one ((word) thread_table[i].context.IntS3); | 
|---|
| 287 | GC_push_one ((word) thread_table[i].context.IntS4); | 
|---|
| 288 | GC_push_one ((word) thread_table[i].context.IntS5); | 
|---|
| 289 | GC_push_one ((word) thread_table[i].context.IntFp); | 
|---|
| 290 | GC_push_one ((word) thread_table[i].context.IntA0); | 
|---|
| 291 | GC_push_one ((word) thread_table[i].context.IntA1); | 
|---|
| 292 | GC_push_one ((word) thread_table[i].context.IntA2); | 
|---|
| 293 | GC_push_one ((word) thread_table[i].context.IntA3); | 
|---|
| 294 | GC_push_one ((word) thread_table[i].context.IntA4); | 
|---|
| 295 | GC_push_one ((word) thread_table[i].context.IntA5); | 
|---|
| 296 | GC_push_one ((word) thread_table[i].context.IntT8); | 
|---|
| 297 | GC_push_one ((word) thread_table[i].context.IntT9); | 
|---|
| 298 | GC_push_one ((word) thread_table[i].context.IntT10); | 
|---|
| 299 | GC_push_one ((word) thread_table[i].context.IntT11); | 
|---|
| 300 | GC_push_one ((word) thread_table[i].context.IntT12); | 
|---|
| 301 | GC_push_one ((word) thread_table[i].context.IntAt); | 
|---|
| 302 | GC_push_all_stack((char *) thread_table[i].context.IntSp, | 
|---|
| 303 | thread_table[i].stack); | 
|---|
| 304 | #       else | 
|---|
| 305 | --> architecture not supported | 
|---|
| 306 | #       endif /* !ALPHA */ | 
|---|
| 307 | #       endif /* !PPC */ | 
|---|
| 308 | #       endif /* !MIPS */ | 
|---|
| 309 | #       endif /* !SHx */ | 
|---|
| 310 | #       endif /* !ARM32 */ | 
|---|
| 311 | #       endif /* !I386 */ | 
|---|
| 312 | } | 
|---|
| 313 | } | 
|---|
| 314 | } | 
|---|
| 315 |  | 
|---|
| 316 | void GC_get_next_stack(char *start, char **lo, char **hi) | 
|---|
| 317 | { | 
|---|
| 318 | int i; | 
|---|
| 319 | #   define ADDR_LIMIT (char *)(-1L) | 
|---|
| 320 | char * current_min = ADDR_LIMIT; | 
|---|
| 321 |  | 
|---|
| 322 | for (i = 0; i < MAX_THREADS; i++) { | 
|---|
| 323 | char * s = (char *)thread_table[i].stack; | 
|---|
| 324 |  | 
|---|
| 325 | if (0 != s && s > start && s < current_min) { | 
|---|
| 326 | current_min = s; | 
|---|
| 327 | } | 
|---|
| 328 | } | 
|---|
| 329 | *hi = current_min; | 
|---|
| 330 | if (current_min == ADDR_LIMIT) { | 
|---|
| 331 | *lo = ADDR_LIMIT; | 
|---|
| 332 | return; | 
|---|
| 333 | } | 
|---|
| 334 | *lo = GC_get_lo_stack_addr(current_min); | 
|---|
| 335 | if (*lo < start) *lo = start; | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 | #if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) | 
|---|
| 339 |  | 
|---|
| 340 | HANDLE WINAPI GC_CreateThread( | 
|---|
| 341 | LPSECURITY_ATTRIBUTES lpThreadAttributes, | 
|---|
| 342 | DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, | 
|---|
| 343 | LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) | 
|---|
| 344 | { | 
|---|
| 345 | return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, | 
|---|
| 346 | lpParameter, dwCreationFlags, lpThreadId); | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|
| 349 | #else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */ | 
|---|
| 350 |  | 
|---|
| 351 | typedef struct { | 
|---|
| 352 | HANDLE child_ready_h, parent_ready_h; | 
|---|
| 353 | volatile struct thread_entry * entry; | 
|---|
| 354 | LPTHREAD_START_ROUTINE start; | 
|---|
| 355 | LPVOID param; | 
|---|
| 356 | } thread_args; | 
|---|
| 357 |  | 
|---|
| 358 | DWORD WINAPI thread_start(LPVOID arg); | 
|---|
| 359 |  | 
|---|
| 360 | HANDLE WINAPI GC_CreateThread( | 
|---|
| 361 | LPSECURITY_ATTRIBUTES lpThreadAttributes, | 
|---|
| 362 | DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, | 
|---|
| 363 | LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) | 
|---|
| 364 | { | 
|---|
| 365 | HANDLE thread_h = NULL; | 
|---|
| 366 | HANDLE child_ready_h, parent_ready_h; | 
|---|
| 367 |  | 
|---|
| 368 | int i; | 
|---|
| 369 | thread_args args; | 
|---|
| 370 |  | 
|---|
| 371 | /* allocate thread slot */ | 
|---|
| 372 | LOCK(); | 
|---|
| 373 | for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++) | 
|---|
| 374 | ; | 
|---|
| 375 | if (i != MAX_THREADS) { | 
|---|
| 376 | thread_table[i].in_use = TRUE; | 
|---|
| 377 | } | 
|---|
| 378 | UNLOCK(); | 
|---|
| 379 |  | 
|---|
| 380 | if (i != MAX_THREADS) { | 
|---|
| 381 |  | 
|---|
| 382 | /* create unnamed unsignalled events */ | 
|---|
| 383 | if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) { | 
|---|
| 384 | if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) { | 
|---|
| 385 |  | 
|---|
| 386 | /* set up thread arguments */ | 
|---|
| 387 | args.child_ready_h = child_ready_h; | 
|---|
| 388 | args.parent_ready_h = parent_ready_h; | 
|---|
| 389 | args.entry = &thread_table[i]; | 
|---|
| 390 | args.start = lpStartAddress; | 
|---|
| 391 | args.param = lpParameter; | 
|---|
| 392 |  | 
|---|
| 393 | thread_h = CreateThread(lpThreadAttributes, | 
|---|
| 394 | dwStackSize, thread_start, | 
|---|
| 395 | &args, | 
|---|
| 396 | dwCreationFlags & ~CREATE_SUSPENDED, | 
|---|
| 397 | lpThreadId); | 
|---|
| 398 |  | 
|---|
| 399 | if (thread_h) { | 
|---|
| 400 |  | 
|---|
| 401 | /* fill in ID and handle; tell child this is done */ | 
|---|
| 402 | thread_table[i].id = *lpThreadId; | 
|---|
| 403 | thread_table[i].handle = thread_h; | 
|---|
| 404 | SetEvent (parent_ready_h); | 
|---|
| 405 |  | 
|---|
| 406 | /* wait for child to fill in stack and copy args */ | 
|---|
| 407 | WaitForSingleObject (child_ready_h, INFINITE); | 
|---|
| 408 |  | 
|---|
| 409 | /* suspend the child if requested */ | 
|---|
| 410 | if (dwCreationFlags & CREATE_SUSPENDED) | 
|---|
| 411 | SuspendThread (thread_h); | 
|---|
| 412 |  | 
|---|
| 413 | /* let child call given function now (or when resumed) */ | 
|---|
| 414 | SetEvent (parent_ready_h); | 
|---|
| 415 |  | 
|---|
| 416 | } else { | 
|---|
| 417 | CloseHandle (parent_ready_h); | 
|---|
| 418 | } | 
|---|
| 419 | } | 
|---|
| 420 | } | 
|---|
| 421 |  | 
|---|
| 422 | CloseHandle (child_ready_h); | 
|---|
| 423 |  | 
|---|
| 424 | if (thread_h == NULL) | 
|---|
| 425 | thread_table[i].in_use = FALSE; | 
|---|
| 426 |  | 
|---|
| 427 | } else { /* no thread slot found */ | 
|---|
| 428 | SetLastError (ERROR_TOO_MANY_TCBS); | 
|---|
| 429 | } | 
|---|
| 430 |  | 
|---|
| 431 | return thread_h; | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | static DWORD WINAPI thread_start(LPVOID arg) | 
|---|
| 435 | { | 
|---|
| 436 | DWORD ret = 0; | 
|---|
| 437 | thread_args args = *(thread_args *)arg; | 
|---|
| 438 |  | 
|---|
| 439 | /* wait for parent to fill in ID and handle */ | 
|---|
| 440 | WaitForSingleObject (args.parent_ready_h, INFINITE); | 
|---|
| 441 | ResetEvent (args.parent_ready_h); | 
|---|
| 442 |  | 
|---|
| 443 | /* fill in stack; tell parent this is done */ | 
|---|
| 444 | args.entry->stack = GC_get_stack_base(); | 
|---|
| 445 | SetEvent (args.child_ready_h); | 
|---|
| 446 |  | 
|---|
| 447 | /* wait for parent to tell us to go (in case it needs to suspend us) */ | 
|---|
| 448 | WaitForSingleObject (args.parent_ready_h, INFINITE); | 
|---|
| 449 | CloseHandle (args.parent_ready_h); | 
|---|
| 450 |  | 
|---|
| 451 | /* Clear the thread entry even if we exit with an exception.        */ | 
|---|
| 452 | /* This is probably pointless, since an uncaught exception is       */ | 
|---|
| 453 | /* supposed to result in the process being killed.                  */ | 
|---|
| 454 | #ifndef __GNUC__ | 
|---|
| 455 | __try { | 
|---|
| 456 | #endif /* __GNUC__ */ | 
|---|
| 457 | ret = args.start (args.param); | 
|---|
| 458 | #ifndef __GNUC__ | 
|---|
| 459 | } __finally { | 
|---|
| 460 | #endif /* __GNUC__ */ | 
|---|
| 461 | LOCK(); | 
|---|
| 462 | args.entry->stack = 0; | 
|---|
| 463 | args.entry->in_use = FALSE; | 
|---|
| 464 | /* cast away volatile qualifier */ | 
|---|
| 465 | BZERO((void *) &args.entry->context, sizeof(CONTEXT)); | 
|---|
| 466 | UNLOCK(); | 
|---|
| 467 | #ifndef __GNUC__ | 
|---|
| 468 | } | 
|---|
| 469 | #endif /* __GNUC__ */ | 
|---|
| 470 |  | 
|---|
| 471 | return ret; | 
|---|
| 472 | } | 
|---|
| 473 | #endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */ | 
|---|
| 474 |  | 
|---|
| 475 | #ifdef MSWINCE | 
|---|
| 476 |  | 
|---|
| 477 | typedef struct { | 
|---|
| 478 | HINSTANCE hInstance; | 
|---|
| 479 | HINSTANCE hPrevInstance; | 
|---|
| 480 | LPWSTR lpCmdLine; | 
|---|
| 481 | int nShowCmd; | 
|---|
| 482 | } main_thread_args; | 
|---|
| 483 |  | 
|---|
| 484 | DWORD WINAPI main_thread_start(LPVOID arg); | 
|---|
| 485 |  | 
|---|
| 486 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | 
|---|
| 487 | LPWSTR lpCmdLine, int nShowCmd) | 
|---|
| 488 | { | 
|---|
| 489 | DWORD exit_code = 1; | 
|---|
| 490 |  | 
|---|
| 491 | main_thread_args args = { | 
|---|
| 492 | hInstance, hPrevInstance, lpCmdLine, nShowCmd | 
|---|
| 493 | }; | 
|---|
| 494 | HANDLE thread_h; | 
|---|
| 495 | DWORD thread_id; | 
|---|
| 496 |  | 
|---|
| 497 | /* initialize everything */ | 
|---|
| 498 | InitializeCriticalSection(&GC_allocate_ml); | 
|---|
| 499 | GC_init(); | 
|---|
| 500 |  | 
|---|
| 501 | /* start the main thread */ | 
|---|
| 502 | thread_h = GC_CreateThread( | 
|---|
| 503 | NULL, 0, main_thread_start, &args, 0, &thread_id); | 
|---|
| 504 |  | 
|---|
| 505 | if (thread_h != NULL) | 
|---|
| 506 | { | 
|---|
| 507 | WaitForSingleObject (thread_h, INFINITE); | 
|---|
| 508 | GetExitCodeThread (thread_h, &exit_code); | 
|---|
| 509 | CloseHandle (thread_h); | 
|---|
| 510 | } | 
|---|
| 511 |  | 
|---|
| 512 | GC_deinit(); | 
|---|
| 513 | DeleteCriticalSection(&GC_allocate_ml); | 
|---|
| 514 |  | 
|---|
| 515 | return (int) exit_code; | 
|---|
| 516 | } | 
|---|
| 517 |  | 
|---|
| 518 | DWORD WINAPI main_thread_start(LPVOID arg) | 
|---|
| 519 | { | 
|---|
| 520 | main_thread_args * args = (main_thread_args *) arg; | 
|---|
| 521 |  | 
|---|
| 522 | return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance, | 
|---|
| 523 | args->lpCmdLine, args->nShowCmd); | 
|---|
| 524 | } | 
|---|
| 525 |  | 
|---|
| 526 | # else /* !MSWINCE */ | 
|---|
| 527 |  | 
|---|
| 528 | LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info); | 
|---|
| 529 |  | 
|---|
| 530 | #ifdef GC_DLL | 
|---|
| 531 |  | 
|---|
| 532 | /* | 
|---|
| 533 | * This isn't generally safe, since DllMain is not premptible. | 
|---|
| 534 | * If another thread holds the lock while this runs we're in trouble. | 
|---|
| 535 | * Pontus Rydin suggests wrapping the thread start routine instead. | 
|---|
| 536 | */ | 
|---|
| 537 | BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) | 
|---|
| 538 | { | 
|---|
| 539 | switch (reason) { | 
|---|
| 540 | case DLL_PROCESS_ATTACH: | 
|---|
| 541 | InitializeCriticalSection(&GC_allocate_ml); | 
|---|
| 542 | GC_init();  /* Force initialization before thread attach.   */ | 
|---|
| 543 | /* fall through */ | 
|---|
| 544 | case DLL_THREAD_ATTACH: | 
|---|
| 545 | { | 
|---|
| 546 | int i; | 
|---|
| 547 | /* It appears to be unsafe to acquire a lock here, since this     */ | 
|---|
| 548 | /* code is apparently not preeemptible on some systems.           */ | 
|---|
| 549 | /* (This is based on complaints, not on Microsoft's official      */ | 
|---|
| 550 | /* documentation, which says this should perform "only simple     */ | 
|---|
| 551 | /* inititalization tasks".)                                       */ | 
|---|
| 552 | /* Hence we make do with nonblocking synchronization.             */ | 
|---|
| 553 |  | 
|---|
| 554 | /* The following should be a noop according to the win32  */ | 
|---|
| 555 | /* documentation.  There is empirical evidence that it    */ | 
|---|
| 556 | /* isn't.         - HB                                    */ | 
|---|
| 557 | #     ifdef MPROTECT_VDB | 
|---|
| 558 | if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); | 
|---|
| 559 | #     endif | 
|---|
| 560 |  | 
|---|
| 561 | for (i = 0; | 
|---|
| 562 | /* cast away volatile qualifier */ | 
|---|
| 563 | InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0; | 
|---|
| 564 | i++) { | 
|---|
| 565 | /* Compare-and-swap would make this cleaner, but that's not     */ | 
|---|
| 566 | /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */ | 
|---|
| 567 | /* InterlockedExchange is supposed to be replaced by            */ | 
|---|
| 568 | /* InterlockedExchangePointer, but that's not really what I     */ | 
|---|
| 569 | /* want here.                                                   */ | 
|---|
| 570 | if (i == MAX_THREADS - 1) | 
|---|
| 571 | ABORT("too many threads"); | 
|---|
| 572 | } | 
|---|
| 573 | thread_table[i].id = GetCurrentThreadId(); | 
|---|
| 574 | if (!DuplicateHandle(GetCurrentProcess(), | 
|---|
| 575 | GetCurrentThread(), | 
|---|
| 576 | GetCurrentProcess(), | 
|---|
| 577 | /* cast away volatile qualifier */ | 
|---|
| 578 | (HANDLE *) &thread_table[i].handle, | 
|---|
| 579 | 0, | 
|---|
| 580 | 0, | 
|---|
| 581 | DUPLICATE_SAME_ACCESS)) { | 
|---|
| 582 | DWORD last_error = GetLastError(); | 
|---|
| 583 | GC_printf1("Last error code: %lx\n", last_error); | 
|---|
| 584 | ABORT("DuplicateHandle failed"); | 
|---|
| 585 | } | 
|---|
| 586 | thread_table[i].stack = GC_get_stack_base(); | 
|---|
| 587 | /* If this thread is being created while we are trying to stop    */ | 
|---|
| 588 | /* the world, wait here.  Hopefully this can't happen on any      */ | 
|---|
| 589 | /* systems that don't allow us to block here.                     */ | 
|---|
| 590 | while (GC_please_stop) Sleep(20); | 
|---|
| 591 | } | 
|---|
| 592 | break; | 
|---|
| 593 | case DLL_THREAD_DETACH: | 
|---|
| 594 | { | 
|---|
| 595 | int i; | 
|---|
| 596 | DWORD thread_id = GetCurrentThreadId(); | 
|---|
| 597 | LOCK(); | 
|---|
| 598 | for (i = 0; | 
|---|
| 599 | i < MAX_THREADS && | 
|---|
| 600 | (thread_table[i].stack == 0 || thread_table[i].id != thread_id); | 
|---|
| 601 | i++) {} | 
|---|
| 602 | if (i >= MAX_THREADS) { | 
|---|
| 603 | WARN("thread %ld not found on detach", (GC_word)thread_id); | 
|---|
| 604 | } else { | 
|---|
| 605 | thread_table[i].stack = 0; | 
|---|
| 606 | thread_table[i].in_use = FALSE; | 
|---|
| 607 | CloseHandle(thread_table[i].handle); | 
|---|
| 608 | /* cast away volatile qualifier */ | 
|---|
| 609 | BZERO((void *) &thread_table[i].context, sizeof(CONTEXT)); | 
|---|
| 610 | } | 
|---|
| 611 | UNLOCK(); | 
|---|
| 612 | } | 
|---|
| 613 | break; | 
|---|
| 614 | case DLL_PROCESS_DETACH: | 
|---|
| 615 | { | 
|---|
| 616 | int i; | 
|---|
| 617 |  | 
|---|
| 618 | LOCK(); | 
|---|
| 619 | for (i = 0; i < MAX_THREADS; ++i) | 
|---|
| 620 | { | 
|---|
| 621 | if (thread_table[i].in_use) | 
|---|
| 622 | { | 
|---|
| 623 | thread_table[i].stack = 0; | 
|---|
| 624 | thread_table[i].in_use = FALSE; | 
|---|
| 625 | CloseHandle(thread_table[i].handle); | 
|---|
| 626 | BZERO((void *) &thread_table[i].context, sizeof(CONTEXT)); | 
|---|
| 627 | } | 
|---|
| 628 | } | 
|---|
| 629 | UNLOCK(); | 
|---|
| 630 |  | 
|---|
| 631 | GC_deinit(); | 
|---|
| 632 | DeleteCriticalSection(&GC_allocate_ml); | 
|---|
| 633 | } | 
|---|
| 634 | break; | 
|---|
| 635 |  | 
|---|
| 636 | } | 
|---|
| 637 | return TRUE; | 
|---|
| 638 | } | 
|---|
| 639 |  | 
|---|
| 640 | #   endif /* GC_DLL */ | 
|---|
| 641 |  | 
|---|
| 642 | # endif /* !MSWINCE */ | 
|---|
| 643 |  | 
|---|
| 644 | #endif /* GC_WIN32_THREADS */ | 
|---|