1
#if defined(GC_WIN32_THREADS)
3
1
#include "private/gc_priv.h"
3
#if defined(GC_WIN32_THREADS)
10
#define MAX_THREADS 64
10
/* Cygwin-specific forward decls */
11
# undef pthread_create
12
# undef pthread_sigmask
16
# define DEBUG_CYGWIN_THREADS 0
18
void * GC_start_routine(void * arg);
19
void GC_thread_exit_proc(void *arg);
23
/* The type of the first argument to InterlockedExchange. */
24
/* Documented to be LONG volatile *, but at least gcc likes */
29
# define MAX_THREADS 256
31
/* Things may get quite slow for large numbers of threads, */
32
/* since we look them up with sequential search. */
35
GC_bool GC_thr_initialized = FALSE;
37
DWORD GC_main_thread = 0;
39
struct GC_thread_Rep {
40
LONG in_use; /* Updated without lock. */
41
/* We assert that unused */
42
/* entries have invalid ids of */
43
/* zero and zero stack fields. */
16
void *stack; /* The cold end of the stack. */
46
ptr_t stack_base; /* The cold end of the stack. */
17
47
/* 0 ==> entry not valid. */
18
/* !in_use ==> stack == 0 */
48
/* !in_use ==> stack_base == 0 */
52
void *status; /* hold exit value until join in case it's a pointer */
54
short flags; /* Protected by GC lock. */
55
# define FINISHED 1 /* Thread has exited. */
56
# define DETACHED 2 /* Thread is intended to be detached. */
60
typedef volatile struct GC_thread_Rep * GC_thread;
63
* We generally assume that volatile ==> memory ordering, at least among
23
67
volatile GC_bool GC_please_stop = FALSE;
25
volatile struct thread_entry thread_table[MAX_THREADS];
69
volatile struct GC_thread_Rep thread_table[MAX_THREADS];
71
volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table */
72
/* that was ever used. */
74
extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
77
* This may be called from DllMain, and hence operates under unusual
80
static GC_thread GC_new_thread(void) {
82
/* It appears to be unsafe to acquire a lock here, since this */
83
/* code is apparently not preeemptible on some systems. */
84
/* (This is based on complaints, not on Microsoft's official */
85
/* documentation, which says this should perform "only simple */
86
/* initialization tasks".) */
87
/* Hence we make do with nonblocking synchronization. */
89
/* The following should be a noop according to the win32 */
90
/* documentation. There is empirical evidence that it */
92
# if defined(MPROTECT_VDB)
93
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
95
/* cast away volatile qualifier */
96
for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) {
97
/* Compare-and-swap would make this cleaner, but that's not */
98
/* supported before Windows 98 and NT 4.0. In Windows 2000, */
99
/* InterlockedExchange is supposed to be replaced by */
100
/* InterlockedExchangePointer, but that's not really what I */
102
if (i == MAX_THREADS - 1)
103
ABORT("too many threads");
105
/* Update GC_max_thread_index if necessary. The following is safe, */
106
/* and unlike CompareExchange-based solutions seems to work on all */
107
/* Windows95 and later platforms. */
108
/* Unfortunately, GC_max_thread_index may be temporarily out of */
109
/* bounds, so readers have to compensate. */
110
while (i > GC_max_thread_index) {
111
InterlockedIncrement((IE_t)&GC_max_thread_index);
113
if (GC_max_thread_index >= MAX_THREADS) {
114
/* We overshot due to simultaneous increments. */
115
/* Setting it to MAX_THREADS-1 is always safe. */
116
GC_max_thread_index = MAX_THREADS - 1;
120
thread_table[i].pthread_id = pthread_self();
122
if (!DuplicateHandle(GetCurrentProcess(),
125
(HANDLE*)&thread_table[i].handle,
128
DUPLICATE_SAME_ACCESS)) {
129
DWORD last_error = GetLastError();
130
GC_printf1("Last error code: %lx\n", last_error);
131
ABORT("DuplicateHandle failed");
133
thread_table[i].stack_base = GC_get_stack_base();
134
/* Up until this point, GC_push_all_stacks considers this thread */
136
if (thread_table[i].stack_base == NULL)
137
ABORT("Failed to find stack base in GC_new_thread");
138
/* Up until this point, this entry is viewed as reserved but invalid */
139
/* by GC_delete_thread. */
140
thread_table[i].id = GetCurrentThreadId();
141
/* If this thread is being created while we are trying to stop */
142
/* the world, wait here. Hopefully this can't happen on any */
143
/* systems that don't allow us to block here. */
144
while (GC_please_stop) Sleep(20);
145
return thread_table + i;
149
* GC_max_thread_index may temporarily be larger than MAX_THREADS.
150
* To avoid subscript errors, we check on access.
155
LONG GC_get_max_thread_index()
157
LONG my_max = GC_max_thread_index;
159
if (my_max >= MAX_THREADS) return MAX_THREADS-1;
163
/* This is intended to be lock-free, though that */
164
/* assumes that the CloseHandle becomes visible before the */
165
/* in_use assignment. */
166
static void GC_delete_gc_thread(GC_thread thr)
168
CloseHandle(thr->handle);
169
/* cast away volatile qualifier */
174
# endif /* CYGWIN32 */
178
static void GC_delete_thread(DWORD thread_id) {
180
LONG my_max = GC_get_max_thread_index();
184
(!thread_table[i].in_use || thread_table[i].id != thread_id);
185
/* Must still be in_use, since nobody else can store our thread_id. */
188
WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id);
190
GC_delete_gc_thread(thread_table+i);
197
/* Return a GC_thread corresponding to a given pthread_t. */
198
/* Returns 0 if it's not there. */
199
/* We assume that this is only called for pthread ids that */
200
/* have not yet terminated or are still joinable. */
201
static GC_thread GC_lookup_thread(pthread_t id)
204
LONG my_max = GC_get_max_thread_index();
208
(!thread_table[i].in_use || thread_table[i].pthread_id != id
209
|| !thread_table[i].in_use);
210
/* Must still be in_use, since nobody else can store our thread_id. */
212
if (i > my_max) return 0;
213
return thread_table + i;
216
#endif /* CYGWIN32 */
27
218
void GC_push_thread_structures GC_PROTO((void))
29
220
/* Unlike the other threads implementations, the thread table here */
30
221
/* contains no pointers to the collectable heap. Thus we have */
31
222
/* no private structures we need to preserve. */
224
{ int i; /* pthreads may keep a pointer in the thread exit value */
225
LONG my_max = GC_get_max_thread_index();
227
for (i = 0; i <= my_max; i++)
228
if (thread_table[i].in_use)
229
GC_push_all((ptr_t)&(thread_table[i].status),
230
(ptr_t)(&(thread_table[i].status)+1));
34
235
void GC_stop_world()
120
330
void GC_push_all_stacks()
122
332
DWORD thread_id = GetCurrentThreadId();
333
GC_bool found_me = FALSE;
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);
338
LONG my_max = GC_get_max_thread_index();
340
for (i = 0; i <= my_max; i++) {
341
thread = thread_table + i;
342
if (thread -> in_use && thread -> stack_base) {
343
if (thread -> id == thread_id) {
348
context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
349
if (!GetThreadContext(thread_table[i].handle, &context))
350
ABORT("GetThreadContext failed");
352
/* Push all registers that might point into the heap. Frame */
353
/* pointer registers are included in case client code was */
354
/* compiled with the 'omit frame pointer' optimisation. */
355
# define PUSH1(reg) GC_push_one((word)context.reg)
356
# define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
357
# define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
359
PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
360
sp = (ptr_t)context.Esp;
361
# elif defined(ARM32)
362
PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
363
sp = (ptr_t)context.Sp;
365
PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
366
PUSH2(R12,R13), PUSH1(R14);
367
sp = (ptr_t)context.R15;
369
PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
370
PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
371
PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
372
PUSH4(IntT9,IntK0,IntK1,IntS8);
373
sp = (ptr_t)context.IntSp;
375
PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
376
PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
377
PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
378
PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
379
sp = (ptr_t)context.Gpr1;
380
# elif defined(ALPHA)
381
PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
382
PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
383
PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
384
PUSH4(IntT10,IntT11,IntT12,IntAt);
385
sp = (ptr_t)context.IntSp;
387
# error "architecture is not supported"
391
stack_min = GC_get_stack_min(thread->stack_base);
393
if (sp >= stack_min && sp < thread->stack_base)
394
GC_push_all_stack(sp, thread->stack_base);
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");
137
if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
138
|| thread_table[i].context.Esp < (DWORD)bottom)
139
ABORT("Thread stack pointer out of range");
140
GC_push_one ((word) thread_table[i].context.Edi);
141
GC_push_one ((word) thread_table[i].context.Esi);
142
GC_push_one ((word) thread_table[i].context.Ebp);
143
GC_push_one ((word) thread_table[i].context.Ebx);
144
GC_push_one ((word) thread_table[i].context.Edx);
145
GC_push_one ((word) thread_table[i].context.Ecx);
146
GC_push_one ((word) thread_table[i].context.Eax);
147
GC_push_all_stack((char *) thread_table[i].context.Esp,
148
thread_table[i].stack);
151
if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack
152
|| thread_table[i].context.Sp < (DWORD)bottom)
153
ABORT("Thread stack pointer out of range");
154
GC_push_one ((word) thread_table[i].context.R0);
155
GC_push_one ((word) thread_table[i].context.R1);
156
GC_push_one ((word) thread_table[i].context.R2);
157
GC_push_one ((word) thread_table[i].context.R3);
158
GC_push_one ((word) thread_table[i].context.R4);
159
GC_push_one ((word) thread_table[i].context.R5);
160
GC_push_one ((word) thread_table[i].context.R6);
161
GC_push_one ((word) thread_table[i].context.R7);
162
GC_push_one ((word) thread_table[i].context.R8);
163
GC_push_one ((word) thread_table[i].context.R9);
164
GC_push_one ((word) thread_table[i].context.R10);
165
GC_push_one ((word) thread_table[i].context.R11);
166
GC_push_one ((word) thread_table[i].context.R12);
167
GC_push_all_stack((char *) thread_table[i].context.Sp,
168
thread_table[i].stack);
171
if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack
172
|| thread_table[i].context.R15 < (DWORD)bottom)
173
ABORT("Thread stack pointer out of range");
174
GC_push_one ((word) thread_table[i].context.R0);
175
GC_push_one ((word) thread_table[i].context.R1);
176
GC_push_one ((word) thread_table[i].context.R2);
177
GC_push_one ((word) thread_table[i].context.R3);
178
GC_push_one ((word) thread_table[i].context.R4);
179
GC_push_one ((word) thread_table[i].context.R5);
180
GC_push_one ((word) thread_table[i].context.R6);
181
GC_push_one ((word) thread_table[i].context.R7);
182
GC_push_one ((word) thread_table[i].context.R8);
183
GC_push_one ((word) thread_table[i].context.R9);
184
GC_push_one ((word) thread_table[i].context.R10);
185
GC_push_one ((word) thread_table[i].context.R11);
186
GC_push_one ((word) thread_table[i].context.R12);
187
GC_push_one ((word) thread_table[i].context.R13);
188
GC_push_one ((word) thread_table[i].context.R14);
189
GC_push_all_stack((char *) thread_table[i].context.R15,
190
thread_table[i].stack);
193
if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
194
|| thread_table[i].context.IntSp < (DWORD)bottom)
195
ABORT("Thread stack pointer out of range");
196
GC_push_one ((word) thread_table[i].context.IntAt);
197
GC_push_one ((word) thread_table[i].context.IntV0);
198
GC_push_one ((word) thread_table[i].context.IntV1);
199
GC_push_one ((word) thread_table[i].context.IntA0);
200
GC_push_one ((word) thread_table[i].context.IntA1);
201
GC_push_one ((word) thread_table[i].context.IntA2);
202
GC_push_one ((word) thread_table[i].context.IntA3);
203
GC_push_one ((word) thread_table[i].context.IntT0);
204
GC_push_one ((word) thread_table[i].context.IntT1);
205
GC_push_one ((word) thread_table[i].context.IntT2);
206
GC_push_one ((word) thread_table[i].context.IntT3);
207
GC_push_one ((word) thread_table[i].context.IntT4);
208
GC_push_one ((word) thread_table[i].context.IntT5);
209
GC_push_one ((word) thread_table[i].context.IntT6);
210
GC_push_one ((word) thread_table[i].context.IntT7);
211
GC_push_one ((word) thread_table[i].context.IntS0);
212
GC_push_one ((word) thread_table[i].context.IntS1);
213
GC_push_one ((word) thread_table[i].context.IntS2);
214
GC_push_one ((word) thread_table[i].context.IntS3);
215
GC_push_one ((word) thread_table[i].context.IntS4);
216
GC_push_one ((word) thread_table[i].context.IntS5);
217
GC_push_one ((word) thread_table[i].context.IntS6);
218
GC_push_one ((word) thread_table[i].context.IntS7);
219
GC_push_one ((word) thread_table[i].context.IntT8);
220
GC_push_one ((word) thread_table[i].context.IntT9);
221
GC_push_one ((word) thread_table[i].context.IntK0);
222
GC_push_one ((word) thread_table[i].context.IntK1);
223
GC_push_one ((word) thread_table[i].context.IntS8);
224
GC_push_all_stack((char *) thread_table[i].context.IntSp,
225
thread_table[i].stack);
228
if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack
229
|| thread_table[i].context.Gpr1 < (DWORD)bottom)
230
ABORT("Thread stack pointer out of range");
231
GC_push_one ((word) thread_table[i].context.Gpr0);
232
/* Gpr1 is stack pointer */
233
/* Gpr2 is global pointer */
234
GC_push_one ((word) thread_table[i].context.Gpr3);
235
GC_push_one ((word) thread_table[i].context.Gpr4);
236
GC_push_one ((word) thread_table[i].context.Gpr5);
237
GC_push_one ((word) thread_table[i].context.Gpr6);
238
GC_push_one ((word) thread_table[i].context.Gpr7);
239
GC_push_one ((word) thread_table[i].context.Gpr8);
240
GC_push_one ((word) thread_table[i].context.Gpr9);
241
GC_push_one ((word) thread_table[i].context.Gpr10);
242
GC_push_one ((word) thread_table[i].context.Gpr11);
243
GC_push_one ((word) thread_table[i].context.Gpr12);
244
/* Gpr13 is reserved for the kernel */
245
GC_push_one ((word) thread_table[i].context.Gpr14);
246
GC_push_one ((word) thread_table[i].context.Gpr15);
247
GC_push_one ((word) thread_table[i].context.Gpr16);
248
GC_push_one ((word) thread_table[i].context.Gpr17);
249
GC_push_one ((word) thread_table[i].context.Gpr18);
250
GC_push_one ((word) thread_table[i].context.Gpr19);
251
GC_push_one ((word) thread_table[i].context.Gpr20);
252
GC_push_one ((word) thread_table[i].context.Gpr21);
253
GC_push_one ((word) thread_table[i].context.Gpr22);
254
GC_push_one ((word) thread_table[i].context.Gpr23);
255
GC_push_one ((word) thread_table[i].context.Gpr24);
256
GC_push_one ((word) thread_table[i].context.Gpr25);
257
GC_push_one ((word) thread_table[i].context.Gpr26);
258
GC_push_one ((word) thread_table[i].context.Gpr27);
259
GC_push_one ((word) thread_table[i].context.Gpr28);
260
GC_push_one ((word) thread_table[i].context.Gpr29);
261
GC_push_one ((word) thread_table[i].context.Gpr30);
262
GC_push_one ((word) thread_table[i].context.Gpr31);
263
GC_push_all_stack((char *) thread_table[i].context.Gpr1,
264
thread_table[i].stack);
267
if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
268
|| thread_table[i].context.IntSp < (DWORD)bottom)
269
ABORT("Thread stack pointer out of range");
270
GC_push_one ((word) thread_table[i].context.IntV0);
271
GC_push_one ((word) thread_table[i].context.IntT0);
272
GC_push_one ((word) thread_table[i].context.IntT1);
273
GC_push_one ((word) thread_table[i].context.IntT2);
274
GC_push_one ((word) thread_table[i].context.IntT3);
275
GC_push_one ((word) thread_table[i].context.IntT4);
276
GC_push_one ((word) thread_table[i].context.IntT5);
277
GC_push_one ((word) thread_table[i].context.IntT6);
278
GC_push_one ((word) thread_table[i].context.IntT7);
279
GC_push_one ((word) thread_table[i].context.IntS0);
280
GC_push_one ((word) thread_table[i].context.IntS1);
281
GC_push_one ((word) thread_table[i].context.IntS2);
282
GC_push_one ((word) thread_table[i].context.IntS3);
283
GC_push_one ((word) thread_table[i].context.IntS4);
284
GC_push_one ((word) thread_table[i].context.IntS5);
285
GC_push_one ((word) thread_table[i].context.IntFp);
286
GC_push_one ((word) thread_table[i].context.IntA0);
287
GC_push_one ((word) thread_table[i].context.IntA1);
288
GC_push_one ((word) thread_table[i].context.IntA2);
289
GC_push_one ((word) thread_table[i].context.IntA3);
290
GC_push_one ((word) thread_table[i].context.IntA4);
291
GC_push_one ((word) thread_table[i].context.IntA5);
292
GC_push_one ((word) thread_table[i].context.IntT8);
293
GC_push_one ((word) thread_table[i].context.IntT9);
294
GC_push_one ((word) thread_table[i].context.IntT10);
295
GC_push_one ((word) thread_table[i].context.IntT11);
296
GC_push_one ((word) thread_table[i].context.IntT12);
297
GC_push_one ((word) thread_table[i].context.IntAt);
298
GC_push_all_stack((char *) thread_table[i].context.IntSp,
299
thread_table[i].stack);
301
--> architecture not supported
396
WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
398
GC_push_all_stack(stack_min, thread->stack_base);
402
if (!found_me) ABORT("Collecting from unknown thread.");
312
405
void GC_get_next_stack(char *start, char **lo, char **hi)
342
440
lpParameter, dwCreationFlags, lpThreadId);
345
#else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
443
#else /* defined(MSWINCE) || !defined(GC_DLL)) */
445
/* We have no DllMain to take care of new threads. Thus we */
446
/* must properly intercept thread creation. */
348
HANDLE child_ready_h, parent_ready_h;
349
volatile struct thread_entry * entry;
350
449
LPTHREAD_START_ROUTINE start;
354
DWORD WINAPI thread_start(LPVOID arg);
453
static DWORD WINAPI thread_start(LPVOID arg);
356
HANDLE WINAPI GC_CreateThread(
455
GC_API HANDLE WINAPI GC_CreateThread(
357
456
LPSECURITY_ATTRIBUTES lpThreadAttributes,
358
457
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
359
458
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
361
460
HANDLE thread_h = NULL;
362
HANDLE child_ready_h, parent_ready_h;
367
/* allocate thread slot */
369
for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
371
if (i != MAX_THREADS) {
372
thread_table[i].in_use = TRUE;
376
if (i != MAX_THREADS) {
378
/* create unnamed unsignalled events */
379
if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
380
if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
382
/* set up thread arguments */
383
args.child_ready_h = child_ready_h;
384
args.parent_ready_h = parent_ready_h;
385
args.entry = &thread_table[i];
386
args.start = lpStartAddress;
387
args.param = lpParameter;
389
thread_h = CreateThread(lpThreadAttributes,
390
dwStackSize, thread_start,
392
dwCreationFlags & ~CREATE_SUSPENDED,
397
/* fill in ID and handle; tell child this is done */
398
thread_table[i].id = *lpThreadId;
399
thread_table[i].handle = thread_h;
400
SetEvent (parent_ready_h);
402
/* wait for child to fill in stack and copy args */
403
WaitForSingleObject (child_ready_h, INFINITE);
405
/* suspend the child if requested */
406
if (dwCreationFlags & CREATE_SUSPENDED)
407
SuspendThread (thread_h);
409
/* let child call given function now (or when resumed) */
410
SetEvent (parent_ready_h);
413
CloseHandle (parent_ready_h);
418
CloseHandle (child_ready_h);
420
if (thread_h == NULL)
421
thread_table[i].in_use = FALSE;
423
} else { /* no thread slot found */
424
SetLastError (ERROR_TOO_MANY_TCBS);
464
if (!GC_is_initialized) GC_init();
465
/* make sure GC is initialized (i.e. main thread is attached) */
467
args = GC_malloc_uncollectable(sizeof(thread_args));
468
/* Handed off to and deallocated by child thread. */
470
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
474
/* set up thread arguments */
475
args -> start = lpStartAddress;
476
args -> param = lpParameter;
478
thread_h = CreateThread(lpThreadAttributes,
479
dwStackSize, thread_start,
480
args, dwCreationFlags,
516
565
# else /* !MSWINCE */
518
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
567
/* Called by GC_init() - we hold the allocation lock. */
569
if (GC_thr_initialized) return;
570
GC_main_thread = GetCurrentThreadId();
571
GC_thr_initialized = TRUE;
573
/* Add the initial thread, so we can stop it. */
580
void *(*start_routine)(void *);
585
int GC_pthread_join(pthread_t pthread_id, void **retval) {
590
# if DEBUG_CYGWIN_THREADS
591
GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",
592
(int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
595
/* Thread being joined might not have registered itself yet. */
596
/* After the join,thread id may have been recycled. */
597
/* FIXME: It would be better if this worked more like */
598
/* pthread_support.c. */
600
while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10);
602
result = pthread_join(pthread_id, retval);
604
GC_delete_gc_thread(me);
606
# if DEBUG_CYGWIN_THREADS
607
GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
608
(int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
614
/* Cygwin-pthreads calls CreateThread internally, but it's not
615
* easily interceptible by us..
616
* so intercept pthread_create instead
619
GC_pthread_create(pthread_t *new_thread,
620
const pthread_attr_t *attr,
621
void *(*start_routine)(void *), void *arg) {
623
struct start_info * si;
625
if (!GC_is_initialized) GC_init();
626
/* make sure GC is initialized (i.e. main thread is attached) */
628
/* This is otherwise saved only in an area mmapped by the thread */
629
/* library, which isn't visible to the collector. */
630
si = GC_malloc_uncollectable(sizeof(struct start_info));
631
if (0 == si) return(EAGAIN);
633
si -> start_routine = start_routine;
636
pthread_attr_getdetachstate(attr, &si->detached)
637
== PTHREAD_CREATE_DETACHED) {
641
# if DEBUG_CYGWIN_THREADS
642
GC_printf2("About to create a thread from 0x%x(0x%x)\n",
643
(int)pthread_self(), GetCurrentThreadId);
645
result = pthread_create(new_thread, attr, GC_start_routine, si);
647
if (result) { /* failure */
654
void * GC_start_routine(void * arg)
656
struct start_info * si = arg;
658
void *(*start)(void *);
660
pthread_t pthread_id;
665
# if DEBUG_CYGWIN_THREADS
666
GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
667
GetCurrentThreadId());
670
/* If a GC occurs before the thread is registered, that GC will */
671
/* ignore this thread. That's fine, since it will block trying to */
672
/* acquire the allocation lock, and won't yet hold interesting */
675
/* We register the thread here instead of in the parent, so that */
676
/* we don't need to hold the allocation lock during pthread_create. */
677
me = GC_new_thread();
680
start = si -> start_routine;
681
start_arg = si -> arg;
682
if (si-> detached) me -> flags |= DETACHED;
683
me -> pthread_id = pthread_id = pthread_self();
685
GC_free(si); /* was allocated uncollectable */
687
pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
688
result = (*start)(start_arg);
689
me -> status = result;
690
pthread_cleanup_pop(0);
692
# if DEBUG_CYGWIN_THREADS
693
GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
694
(int)pthread_self(),GetCurrentThreadId());
700
void GC_thread_exit_proc(void *arg)
702
GC_thread me = (GC_thread)arg;
705
# if DEBUG_CYGWIN_THREADS
706
GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
707
(int)pthread_self(),GetCurrentThreadId());
711
if (me -> flags & DETACHED) {
712
GC_delete_thread(GetCurrentThreadId());
714
/* deallocate it as part of join */
715
me -> flags |= FINISHED;
720
/* nothing required here... */
721
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
722
return pthread_sigmask(how, set, oset);
725
int GC_pthread_detach(pthread_t thread)
728
GC_thread thread_gc_id;
731
thread_gc_id = GC_lookup_thread(thread);
733
result = pthread_detach(thread);
736
thread_gc_id -> flags |= DETACHED;
737
/* Here the pthread thread id may have been recycled. */
738
if (thread_gc_id -> flags & FINISHED) {
739
GC_delete_gc_thread(thread_gc_id);
746
#else /* !CYGWIN32 */
521
* This isn't generally safe, since DllMain is not premptible.
522
* If another thread holds the lock while this runs we're in trouble.
749
* We avoid acquiring locks here, since this doesn't seem to be preemptable.
523
750
* Pontus Rydin suggests wrapping the thread start routine instead.
525
753
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
527
755
switch (reason) {
528
756
case DLL_PROCESS_ATTACH:
529
InitializeCriticalSection(&GC_allocate_ml);
530
757
GC_init(); /* Force initialization before thread attach. */
531
758
/* fall through */
532
759
case DLL_THREAD_ATTACH:
535
/* It appears to be unsafe to acquire a lock here, since this */
536
/* code is apparently not preeemptible on some systems. */
537
/* (This is based on complaints, not on Microsoft's official */
538
/* documentation, which says this should perform "only simple */
539
/* inititalization tasks".) */
540
/* Hence we make do with nonblocking synchronization. */
542
/* The following should be a noop according to the win32 */
543
/* documentation. There is empirical evidence that it */
546
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
550
/* cast away volatile qualifier */
551
InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
553
/* Compare-and-swap would make this cleaner, but that's not */
554
/* supported before Windows 98 and NT 4.0. In Windows 2000, */
555
/* InterlockedExchange is supposed to be replaced by */
556
/* InterlockedExchangePointer, but that's not really what I */
558
if (i == MAX_THREADS - 1)
559
ABORT("too many threads");
561
thread_table[i].id = GetCurrentThreadId();
562
if (!DuplicateHandle(GetCurrentProcess(),
565
/* cast away volatile qualifier */
566
(HANDLE *) &thread_table[i].handle,
569
DUPLICATE_SAME_ACCESS)) {
570
DWORD last_error = GetLastError();
571
GC_printf1("Last error code: %lx\n", last_error);
572
ABORT("DuplicateHandle failed");
574
thread_table[i].stack = GC_get_stack_base();
575
/* If this thread is being created while we are trying to stop */
576
/* the world, wait here. Hopefully this can't happen on any */
577
/* systems that don't allow us to block here. */
578
while (GC_please_stop) Sleep(20);
760
GC_ASSERT(GC_thr_initialized);
761
if (GC_main_thread != GetCurrentThreadId()) {
763
} /* o.w. we already did it during GC_thr_init(), called by GC_init() */
581
766
case DLL_THREAD_DETACH:
584
DWORD thread_id = GetCurrentThreadId();
588
(thread_table[i].stack == 0 || thread_table[i].id != thread_id);
590
if (i >= MAX_THREADS) {
591
WARN("thread %ld not found on detach", (GC_word)thread_id);
593
thread_table[i].stack = 0;
594
thread_table[i].in_use = FALSE;
595
CloseHandle(thread_table[i].handle);
596
/* cast away volatile qualifier */
597
BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
767
GC_delete_thread(GetCurrentThreadId());
602
770
case DLL_PROCESS_DETACH:
607
for (i = 0; i < MAX_THREADS; ++i)
775
for (i = 0; i <= GC_get_max_thread_index(); ++i)
609
777
if (thread_table[i].in_use)
611
thread_table[i].stack = 0;
612
thread_table[i].in_use = FALSE;
613
CloseHandle(thread_table[i].handle);
614
BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
778
GC_delete_gc_thread(thread_table + i);