| 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 */
|
|---|