1 /*
2 * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
4 * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
5 * Copyright (c) 2000-2008 by Hewlett-Packard Development Company.
6 * All rights reserved.
7 *
8 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
9 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 *
11 * Permission is hereby granted to use or copy this program
12 * for any purpose, provided the above notices are retained on all copies.
13 * Permission to modify the code and to distribute modified code is granted,
14 * provided the above notices are retained, and a notice that the code was
15 * modified is included with the above copyright notice.
16 */
17
18 #include "private/gc_priv.h"
19
20 #if defined(GC_WIN32_THREADS)
21
22 #ifndef WIN32_LEAN_AND_MEAN
23 # define WIN32_LEAN_AND_MEAN 1
24 #endif
25 #define NOSERVICE
26 #include <windows.h>
27
28 #ifdef THREAD_LOCAL_ALLOC
29 # include "private/thread_local_alloc.h"
30 #endif /* THREAD_LOCAL_ALLOC */
31
32 /* Allocation lock declarations. */
33 #if !defined(USE_PTHREAD_LOCKS)
34 GC_INNER CRITICAL_SECTION GC_allocate_ml;
35 # ifdef GC_ASSERTIONS
36 GC_INNER DWORD GC_lock_holder = NO_THREAD;
37 /* Thread id for current holder of allocation lock */
38 # endif
39 #else
40 GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
41 # ifdef GC_ASSERTIONS
42 GC_INNER unsigned long GC_lock_holder = NO_THREAD;
43 # endif
44 #endif
45
46 #undef CreateThread
47 #undef ExitThread
48 #undef _beginthreadex
49 #undef _endthreadex
50
51 #ifdef GC_PTHREADS
52 # include <errno.h> /* for EAGAIN */
53
54 /* Cygwin-specific forward decls */
55 # undef pthread_create
56 # undef pthread_join
57 # undef pthread_detach
58
59 # ifndef GC_NO_PTHREAD_SIGMASK
60 # undef pthread_sigmask
61 # endif
62
63 STATIC void * GC_pthread_start(void * arg);
64 STATIC void GC_thread_exit_proc(void *arg);
65
66 # include <pthread.h>
67 # ifdef CAN_CALL_ATFORK
68 # include <unistd.h>
69 # endif
70
71 #elif !defined(MSWINCE)
72 # include <process.h> /* For _beginthreadex, _endthreadex */
73 # include <errno.h> /* for errno, EAGAIN */
74
75 #endif /* !GC_PTHREADS && !MSWINCE */
76
77 /* PUSHED_REGS_COUNT is the number of copied registers in copy_ptr_regs. */
78 static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext);
79 #if defined(I386)
80 # ifdef WOW64_THREAD_CONTEXT_WORKAROUND
81 # define PUSHED_REGS_COUNT 9
82 # else
83 # define PUSHED_REGS_COUNT 7
84 # endif
85 #elif defined(X86_64) || defined(SHx)
86 # define PUSHED_REGS_COUNT 15
87 #elif defined(ARM32)
88 # define PUSHED_REGS_COUNT 13
89 #elif defined(AARCH64)
90 # define PUSHED_REGS_COUNT 30
91 #elif defined(MIPS) || defined(ALPHA)
92 # define PUSHED_REGS_COUNT 28
93 #elif defined(PPC)
94 # define PUSHED_REGS_COUNT 29
95 #endif
96
97 /* DllMain-based thread registration is currently incompatible */
98 /* with thread-local allocation, pthreads and WinCE. */
99 #if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) \
100 && !defined(GC_NO_THREADS_DISCOVERY) && !defined(MSWINCE) \
101 && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
102
103 /* This code operates in two distinct modes, depending on */
104 /* the setting of GC_win32_dll_threads. */
105 /* If GC_win32_dll_threads is set, all threads in the process */
106 /* are implicitly registered with the GC by DllMain. */
107 /* No explicit registration is required, and attempts at */
108 /* explicit registration are ignored. This mode is */
109 /* very different from the Posix operation of the collector. */
110 /* In this mode access to the thread table is lock-free. */
111 /* Hence there is a static limit on the number of threads. */
112
113 # ifdef GC_DISCOVER_TASK_THREADS
114 /* GC_DISCOVER_TASK_THREADS should be used if DllMain-based */
115 /* thread registration is required but it is impossible to */
116 /* call GC_use_threads_discovery before other GC routines. */
117 # define GC_win32_dll_threads TRUE
118 # else
119 STATIC GC_bool GC_win32_dll_threads = FALSE;
120 /* GC_win32_dll_threads must be set (if needed) at the */
121 /* application initialization time, i.e. before any */
122 /* collector or thread calls. We make it a "dynamic" */
123 /* option only to avoid multiple library versions. */
124 # endif
125
126 #else
127 /* If GC_win32_dll_threads is FALSE (or the collector is */
128 /* built without GC_DLL defined), things operate in a way */
129 /* that is very similar to Posix platforms, and new threads */
130 /* must be registered with the collector, e.g. by using */
131 /* preprocessor-based interception of the thread primitives. */
132 /* In this case, we use a real data structure for the thread */
133 /* table. Note that there is no equivalent of linker-based */
134 /* call interception, since we don't have ELF-like */
135 /* facilities. The Windows analog appears to be "API */
136 /* hooking", which really seems to be a standard way to */
137 /* do minor binary rewriting (?). I'd prefer not to have */
138 /* the basic collector rely on such facilities, but an */
139 /* optional package that intercepts thread calls this way */
140 /* would probably be nice. */
141 # ifndef GC_NO_THREADS_DISCOVERY
142 # define GC_NO_THREADS_DISCOVERY
143 # endif
144 # define GC_win32_dll_threads FALSE
145 # undef MAX_THREADS
146 # define MAX_THREADS 1 /* dll_thread_table[] is always empty. */
147 #endif /* GC_NO_THREADS_DISCOVERY */
148
149 /* We have two versions of the thread table. Which one */
150 /* we us depends on whether or not GC_win32_dll_threads */
151 /* is set. Note that before initialization, we don't */
152 /* add any entries to either table, even if DllMain is */
153 /* called. The main thread will be added on */
154 /* initialization. */
155
156 /* The type of the first argument to InterlockedExchange. */
157 /* Documented to be LONG volatile *, but at least gcc likes */
158 /* this better. */
159 typedef LONG * IE_t;
160
161 STATIC GC_bool GC_thr_initialized = FALSE;
162
163 #ifndef GC_ALWAYS_MULTITHREADED
164 GC_INNER GC_bool GC_need_to_lock = FALSE;
165 #endif
166
167 static GC_bool parallel_initialized = FALSE;
168
169 /* GC_use_threads_discovery() is currently incompatible with pthreads */
170 /* and WinCE. It might be possible to get DllMain-based thread */
171 /* registration to work with Cygwin, but if you try it then you are on */
172 /* your own. */
GC_use_threads_discovery(void)173 GC_API void GC_CALL GC_use_threads_discovery(void)
174 {
175 # ifdef GC_NO_THREADS_DISCOVERY
176 ABORT("GC DllMain-based thread registration unsupported");
177 # else
178 /* Turn on GC_win32_dll_threads. */
179 GC_ASSERT(!parallel_initialized);
180 /* Note that GC_use_threads_discovery is expected to be called by */
181 /* the client application (not from DllMain) at start-up. */
182 # ifndef GC_DISCOVER_TASK_THREADS
183 GC_win32_dll_threads = TRUE;
184 # endif
185 GC_init_parallel();
186 # endif
187 }
188
189 STATIC DWORD GC_main_thread = 0;
190
191 #define ADDR_LIMIT ((ptr_t)GC_WORD_MAX)
192
193 struct GC_Thread_Rep {
194 union {
195 # ifndef GC_NO_THREADS_DISCOVERY
196 volatile AO_t in_use;
197 /* Updated without lock. */
198 /* We assert that unused */
199 /* entries have invalid ids of */
200 /* zero and zero stack fields. */
201 /* Used only with GC_win32_dll_threads. */
202 LONG long_in_use; /* The same but of the type that */
203 /* matches the first argument of */
204 /* InterlockedExchange(); volatile is */
205 /* omitted because the ancient version */
206 /* of the prototype lacks the qualifier.*/
207 # endif
208 struct GC_Thread_Rep * next;
209 /* Hash table link without */
210 /* GC_win32_dll_threads. */
211 /* More recently allocated threads */
212 /* with a given pthread id come */
213 /* first. (All but the first are */
214 /* guaranteed to be dead, but we may */
215 /* not yet have registered the join.) */
216 } tm; /* table_management */
217 DWORD id;
218
219 # ifdef MSWINCE
220 /* According to MSDN specs for WinCE targets: */
221 /* - DuplicateHandle() is not applicable to thread handles; and */
222 /* - the value returned by GetCurrentThreadId() could be used as */
223 /* a "real" thread handle (for SuspendThread(), ResumeThread() and */
224 /* GetThreadContext()). */
225 # define THREAD_HANDLE(t) (HANDLE)(word)(t)->id
226 # else
227 HANDLE handle;
228 # define THREAD_HANDLE(t) (t)->handle
229 # endif
230
231 ptr_t stack_base; /* The cold end of the stack. */
232 /* 0 ==> entry not valid. */
233 /* !in_use ==> stack_base == 0 */
234 ptr_t last_stack_min; /* Last known minimum (hottest) address */
235 /* in stack or ADDR_LIMIT if unset */
236 # ifdef IA64
237 ptr_t backing_store_end;
238 ptr_t backing_store_ptr;
239 # endif
240
241 ptr_t thread_blocked_sp; /* Protected by GC lock. */
242 /* NULL value means thread unblocked. */
243 /* If set to non-NULL, thread will */
244 /* acquire GC lock before doing any */
245 /* pointer manipulations. Thus it does */
246 /* not need to stop this thread. */
247
248 struct GC_traced_stack_sect_s *traced_stack_sect;
249 /* Points to the "stack section" data */
250 /* held in stack by the innermost */
251 /* GC_call_with_gc_active() of this */
252 /* thread. May be NULL. */
253
254 unsigned short finalizer_skipped;
255 unsigned char finalizer_nested;
256 /* Used by GC_check_finalizer_nested() */
257 /* to minimize the level of recursion */
258 /* when a client finalizer allocates */
259 /* memory (initially both are 0). */
260
261 unsigned char suspended; /* really of GC_bool type */
262
263 # ifdef GC_PTHREADS
264 unsigned char flags; /* Protected by GC lock. */
265 # define FINISHED 1 /* Thread has exited. */
266 # define DETACHED 2 /* Thread is intended to be detached. */
267 # define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
268 pthread_t pthread_id;
269 void *status; /* hold exit value until join in case it's a pointer */
270 # else
271 # define KNOWN_FINISHED(t) 0
272 # endif
273
274 # ifdef THREAD_LOCAL_ALLOC
275 struct thread_local_freelists tlfs;
276 # endif
277
278 # ifdef RETRY_GET_THREAD_CONTEXT
279 ptr_t context_sp;
280 word context_regs[PUSHED_REGS_COUNT];
281 /* Populated as part of GC_suspend() as */
282 /* resume/suspend loop may be needed for the */
283 /* call to GetThreadContext() to succeed. */
284 # endif
285 };
286
287 typedef struct GC_Thread_Rep * GC_thread;
288 typedef volatile struct GC_Thread_Rep * GC_vthread;
289
290 #ifndef GC_NO_THREADS_DISCOVERY
291 /* We assumed that volatile ==> memory ordering, at least among */
292 /* volatiles. This code should consistently use atomic_ops. */
293 STATIC volatile GC_bool GC_please_stop = FALSE;
294 #elif defined(GC_ASSERTIONS)
295 STATIC GC_bool GC_please_stop = FALSE;
296 #endif
297
298 /*
299 * We track thread attachments while the world is supposed to be stopped.
300 * Unfortunately, we can't stop them from starting, since blocking in
301 * DllMain seems to cause the world to deadlock. Thus we have to recover
302 * If we notice this in the middle of marking.
303 */
304
305 #ifndef GC_NO_THREADS_DISCOVERY
306 STATIC volatile AO_t GC_attached_thread = FALSE;
307 #endif
308
309 #if defined(WRAP_MARK_SOME) && !defined(GC_PTHREADS)
310 /* Return TRUE if an thread was attached since we last asked or */
311 /* since GC_attached_thread was explicitly reset. */
GC_started_thread_while_stopped(void)312 GC_INNER GC_bool GC_started_thread_while_stopped(void)
313 {
314 # ifndef GC_NO_THREADS_DISCOVERY
315 if (GC_win32_dll_threads) {
316 # ifdef AO_HAVE_compare_and_swap_release
317 if (AO_compare_and_swap_release(&GC_attached_thread, TRUE,
318 FALSE /* stored */))
319 return TRUE;
320 # else
321 AO_nop_full(); /* Prior heap reads need to complete earlier. */
322 if (AO_load(&GC_attached_thread)) {
323 AO_store(&GC_attached_thread, FALSE);
324 return TRUE;
325 }
326 # endif
327 }
328 # endif
329 return FALSE;
330 }
331 #endif /* WRAP_MARK_SOME */
332
333 /* Thread table used if GC_win32_dll_threads is set. */
334 /* This is a fixed size array. */
335 /* Since we use runtime conditionals, both versions */
336 /* are always defined. */
337 # ifndef MAX_THREADS
338 # define MAX_THREADS 512
339 # endif
340
341 /* Things may get quite slow for large numbers of threads, */
342 /* since we look them up with sequential search. */
343 volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
344
345 STATIC volatile LONG GC_max_thread_index = 0;
346 /* Largest index in dll_thread_table */
347 /* that was ever used. */
348
349 /* And now the version used if GC_win32_dll_threads is not set. */
350 /* This is a chained hash table, with much of the code borrowed */
351 /* from the Posix implementation. */
352 #ifndef THREAD_TABLE_SZ
353 # define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */
354 #endif
355 #define THREAD_TABLE_INDEX(id) /* id is of DWORD type */ \
356 (int)((((id) >> 8) ^ (id)) % THREAD_TABLE_SZ)
357 STATIC GC_thread GC_threads[THREAD_TABLE_SZ];
358
359 /* It may not be safe to allocate when we register the first thread. */
360 /* Thus we allocated one statically. It does not contain any pointer */
361 /* field we need to push ("next" and "status" fields are unused). */
362 static struct GC_Thread_Rep first_thread;
363 static GC_bool first_thread_used = FALSE;
364
365 /* Add a thread to GC_threads. We assume it wasn't already there. */
366 /* Caller holds allocation lock. */
367 /* Unlike the pthreads version, the id field is set by the caller. */
GC_new_thread(DWORD id)368 STATIC GC_thread GC_new_thread(DWORD id)
369 {
370 int hv = THREAD_TABLE_INDEX(id);
371 GC_thread result;
372
373 # ifdef DEBUG_THREADS
374 GC_log_printf("Creating thread 0x%lx\n", (long)id);
375 if (GC_threads[hv] != NULL)
376 GC_log_printf("Hash collision at GC_threads[%d]\n", hv);
377 # endif
378 GC_ASSERT(I_HOLD_LOCK());
379 if (!EXPECT(first_thread_used, TRUE)) {
380 result = &first_thread;
381 first_thread_used = TRUE;
382 GC_ASSERT(NULL == GC_threads[hv]);
383 } else {
384 GC_ASSERT(!GC_win32_dll_threads);
385 result = (struct GC_Thread_Rep *)
386 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
387 if (result == 0) return(0);
388 }
389 /* result -> id = id; Done by caller. */
390 result -> tm.next = GC_threads[hv];
391 GC_threads[hv] = result;
392 # ifdef GC_PTHREADS
393 GC_ASSERT(result -> flags == 0);
394 # endif
395 GC_ASSERT(result -> thread_blocked_sp == NULL);
396 if (EXPECT(result != &first_thread, TRUE))
397 GC_dirty(result);
398 return(result);
399 }
400
401 GC_INNER GC_bool GC_in_thread_creation = FALSE;
402 /* Protected by allocation lock. */
403
GC_record_stack_base(GC_vthread me,const struct GC_stack_base * sb)404 GC_INLINE void GC_record_stack_base(GC_vthread me,
405 const struct GC_stack_base *sb)
406 {
407 me -> stack_base = (ptr_t)sb->mem_base;
408 # ifdef IA64
409 me -> backing_store_end = (ptr_t)sb->reg_base;
410 # endif
411 if (me -> stack_base == NULL)
412 ABORT("Bad stack base in GC_register_my_thread");
413 }
414
415 /* This may be called from DllMain, and hence operates under unusual */
416 /* constraints. In particular, it must be lock-free if */
417 /* GC_win32_dll_threads is set. Always called from the thread being */
418 /* added. If GC_win32_dll_threads is not set, we already hold the */
419 /* allocation lock except possibly during single-threaded startup code. */
GC_register_my_thread_inner(const struct GC_stack_base * sb,DWORD thread_id)420 STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
421 DWORD thread_id)
422 {
423 GC_vthread me;
424
425 /* The following should be a no-op according to the win32 */
426 /* documentation. There is empirical evidence that it */
427 /* isn't. - HB */
428 # if defined(MPROTECT_VDB) && !defined(CYGWIN32)
429 if (GC_auto_incremental
430 # ifdef GWW_VDB
431 && !GC_gww_dirty_init()
432 # endif
433 )
434 GC_set_write_fault_handler();
435 # endif
436
437 # ifndef GC_NO_THREADS_DISCOVERY
438 if (GC_win32_dll_threads) {
439 int i;
440 /* It appears to be unsafe to acquire a lock here, since this */
441 /* code is apparently not preemptible on some systems. */
442 /* (This is based on complaints, not on Microsoft's official */
443 /* documentation, which says this should perform "only simple */
444 /* initialization tasks".) */
445 /* Hence we make do with nonblocking synchronization. */
446 /* It has been claimed that DllMain is really only executed with */
447 /* a particular system lock held, and thus careful use of locking */
448 /* around code that doesn't call back into the system libraries */
449 /* might be OK. But this hasn't been tested across all win32 */
450 /* variants. */
451 for (i = 0;
452 InterlockedExchange(&dll_thread_table[i].tm.long_in_use, 1) != 0;
453 i++) {
454 /* Compare-and-swap would make this cleaner, but that's not */
455 /* supported before Windows 98 and NT 4.0. In Windows 2000, */
456 /* InterlockedExchange is supposed to be replaced by */
457 /* InterlockedExchangePointer, but that's not really what I */
458 /* want here. */
459 /* FIXME: We should eventually declare Win95 dead and use AO_ */
460 /* primitives here. */
461 if (i == MAX_THREADS - 1)
462 ABORT("Too many threads");
463 }
464 /* Update GC_max_thread_index if necessary. The following is */
465 /* safe, and unlike CompareExchange-based solutions seems to work */
466 /* on all Windows95 and later platforms. */
467 /* Unfortunately, GC_max_thread_index may be temporarily out of */
468 /* bounds, so readers have to compensate. */
469 while (i > GC_max_thread_index) {
470 InterlockedIncrement((IE_t)&GC_max_thread_index);
471 }
472 if (GC_max_thread_index >= MAX_THREADS) {
473 /* We overshot due to simultaneous increments. */
474 /* Setting it to MAX_THREADS-1 is always safe. */
475 GC_max_thread_index = MAX_THREADS - 1;
476 }
477 me = dll_thread_table + i;
478 } else
479 # endif
480 /* else */ /* Not using DllMain */ {
481 GC_ASSERT(I_HOLD_LOCK());
482 GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
483 me = GC_new_thread(thread_id);
484 GC_in_thread_creation = FALSE;
485 if (me == 0)
486 ABORT("Failed to allocate memory for thread registering");
487 }
488 # ifdef GC_PTHREADS
489 /* me can be NULL -> segfault */
490 me -> pthread_id = pthread_self();
491 # endif
492 # ifndef MSWINCE
493 /* GetCurrentThread() returns a pseudohandle (a const value). */
494 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
495 GetCurrentProcess(),
496 (HANDLE*)&(me -> handle),
497 0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
498 DUPLICATE_SAME_ACCESS)) {
499 ABORT_ARG1("DuplicateHandle failed",
500 ": errcode= 0x%X", (unsigned)GetLastError());
501 }
502 # endif
503 me -> last_stack_min = ADDR_LIMIT;
504 GC_record_stack_base(me, sb);
505 /* Up until this point, GC_push_all_stacks considers this thread */
506 /* invalid. */
507 /* Up until this point, this entry is viewed as reserved but invalid */
508 /* by GC_delete_thread. */
509 me -> id = thread_id;
510 # if defined(THREAD_LOCAL_ALLOC)
511 GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
512 # endif
513 # ifndef GC_NO_THREADS_DISCOVERY
514 if (GC_win32_dll_threads) {
515 if (GC_please_stop) {
516 AO_store(&GC_attached_thread, TRUE);
517 AO_nop_full(); /* Later updates must become visible after this. */
518 }
519 /* We'd like to wait here, but can't, since waiting in DllMain */
520 /* provokes deadlocks. */
521 /* Thus we force marking to be restarted instead. */
522 } else
523 # endif
524 /* else */ {
525 GC_ASSERT(!GC_please_stop);
526 /* Otherwise both we and the thread stopping code would be */
527 /* holding the allocation lock. */
528 }
529 return (GC_thread)(me);
530 }
531
532 /*
533 * GC_max_thread_index may temporarily be larger than MAX_THREADS.
534 * To avoid subscript errors, we check on access.
535 */
GC_get_max_thread_index(void)536 GC_INLINE LONG GC_get_max_thread_index(void)
537 {
538 LONG my_max = GC_max_thread_index;
539 if (my_max >= MAX_THREADS) return MAX_THREADS - 1;
540 return my_max;
541 }
542
543 /* Return the GC_thread corresponding to a thread id. May be called */
544 /* without a lock, but should be called in contexts in which the */
545 /* requested thread cannot be asynchronously deleted, e.g. from the */
546 /* thread itself. */
547 /* This version assumes that either GC_win32_dll_threads is set, or */
548 /* we hold the allocator lock. */
549 /* Also used (for assertion checking only) from thread_local_alloc.c. */
GC_lookup_thread_inner(DWORD thread_id)550 STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
551 {
552 # ifndef GC_NO_THREADS_DISCOVERY
553 if (GC_win32_dll_threads) {
554 int i;
555 LONG my_max = GC_get_max_thread_index();
556 for (i = 0; i <= my_max &&
557 (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
558 || dll_thread_table[i].id != thread_id);
559 /* Must still be in_use, since nobody else can store our */
560 /* thread_id. */
561 i++) {
562 /* empty */
563 }
564 return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
565 } else
566 # endif
567 /* else */ {
568 GC_thread p = GC_threads[THREAD_TABLE_INDEX(thread_id)];
569
570 GC_ASSERT(I_HOLD_LOCK());
571 while (p != 0 && p -> id != thread_id) p = p -> tm.next;
572 return(p);
573 }
574 }
575
576 #ifdef LINT2
577 # define CHECK_LOOKUP_MY_THREAD(me) \
578 if (!(me)) ABORT("GC_lookup_thread_inner(GetCurrentThreadId) failed")
579 #else
580 # define CHECK_LOOKUP_MY_THREAD(me) /* empty */
581 #endif
582
583 /* Called by GC_finalize() (in case of an allocation failure observed). */
584 /* GC_reset_finalizer_nested() is the same as in pthread_support.c. */
GC_reset_finalizer_nested(void)585 GC_INNER void GC_reset_finalizer_nested(void)
586 {
587 GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
588 CHECK_LOOKUP_MY_THREAD(me);
589 me->finalizer_nested = 0;
590 }
591
592 /* Checks and updates the thread-local level of finalizers recursion. */
593 /* Returns NULL if GC_invoke_finalizers() should not be called by the */
594 /* collector (to minimize the risk of a deep finalizers recursion), */
595 /* otherwise returns a pointer to the thread-local finalizer_nested. */
596 /* Called by GC_notify_or_invoke_finalizers() only (the lock is held). */
597 /* GC_check_finalizer_nested() is the same as in pthread_support.c. */
GC_check_finalizer_nested(void)598 GC_INNER unsigned char *GC_check_finalizer_nested(void)
599 {
600 GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
601 unsigned nesting_level;
602 CHECK_LOOKUP_MY_THREAD(me);
603 nesting_level = me->finalizer_nested;
604 if (nesting_level) {
605 /* We are inside another GC_invoke_finalizers(). */
606 /* Skip some implicitly-called GC_invoke_finalizers() */
607 /* depending on the nesting (recursion) level. */
608 if (++me->finalizer_skipped < (1U << nesting_level)) return NULL;
609 me->finalizer_skipped = 0;
610 }
611 me->finalizer_nested = (unsigned char)(nesting_level + 1);
612 return &me->finalizer_nested;
613 }
614
615 #if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
616 /* This is called from thread-local GC_malloc(). */
GC_is_thread_tsd_valid(void * tsd)617 GC_bool GC_is_thread_tsd_valid(void *tsd)
618 {
619 GC_thread me;
620 DCL_LOCK_STATE;
621
622 LOCK();
623 me = GC_lookup_thread_inner(GetCurrentThreadId());
624 UNLOCK();
625 return (word)tsd >= (word)(&me->tlfs)
626 && (word)tsd < (word)(&me->tlfs) + sizeof(me->tlfs);
627 }
628 #endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */
629
GC_thread_is_registered(void)630 GC_API int GC_CALL GC_thread_is_registered(void)
631 {
632 DWORD thread_id = GetCurrentThreadId();
633 GC_thread me;
634 DCL_LOCK_STATE;
635
636 LOCK();
637 me = GC_lookup_thread_inner(thread_id);
638 UNLOCK();
639 return me != NULL;
640 }
641
GC_register_altstack(void * stack GC_ATTR_UNUSED,GC_word stack_size GC_ATTR_UNUSED,void * altstack GC_ATTR_UNUSED,GC_word altstack_size GC_ATTR_UNUSED)642 GC_API void GC_CALL GC_register_altstack(void *stack GC_ATTR_UNUSED,
643 GC_word stack_size GC_ATTR_UNUSED,
644 void *altstack GC_ATTR_UNUSED,
645 GC_word altstack_size GC_ATTR_UNUSED)
646 {
647 /* TODO: Implement */
648 }
649
650 /* Make sure thread descriptor t is not protected by the VDB */
651 /* implementation. */
652 /* Used to prevent write faults when the world is (partially) stopped, */
653 /* since it may have been stopped with a system lock held, and that */
654 /* lock may be required for fault handling. */
655 #if defined(MPROTECT_VDB)
656 # define UNPROTECT_THREAD(t) \
657 if (!GC_win32_dll_threads && GC_auto_incremental \
658 && t != &first_thread) { \
659 GC_ASSERT(SMALL_OBJ(GC_size(t))); \
660 GC_remove_protection(HBLKPTR(t), 1, FALSE); \
661 } else (void)0
662 #else
663 # define UNPROTECT_THREAD(t) (void)0
664 #endif
665
666 #ifdef CYGWIN32
667 # define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
668 #elif defined(GC_WIN32_PTHREADS) || defined(GC_PTHREADS_PARAMARK)
669 # include <pthread.h> /* to check for winpthreads */
670 # if defined(__WINPTHREADS_VERSION_MAJOR)
671 # define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
672 # else
673 # define GC_PTHREAD_PTRVAL(pthread_id) pthread_id.p
674 # endif
675 #endif
676
677 /* If a thread has been joined, but we have not yet */
678 /* been notified, then there may be more than one thread */
679 /* in the table with the same win32 id. */
680 /* This is OK, but we need a way to delete a specific one. */
681 /* Assumes we hold the allocation lock unless */
682 /* GC_win32_dll_threads is set. Does not actually free */
683 /* GC_thread entry (only unlinks it). */
684 /* If GC_win32_dll_threads is set it should be called from the */
685 /* thread being deleted. */
GC_delete_gc_thread_no_free(GC_vthread t)686 STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
687 {
688 # ifndef MSWINCE
689 CloseHandle(t->handle);
690 # endif
691 # ifndef GC_NO_THREADS_DISCOVERY
692 if (GC_win32_dll_threads) {
693 /* This is intended to be lock-free. */
694 /* It is either called synchronously from the thread being */
695 /* deleted, or by the joining thread. */
696 /* In this branch asynchronous changes to (*t) are possible. */
697 /* It's not allowed to call GC_printf (and the friends) here, */
698 /* see GC_stop_world() for the information. */
699 t -> stack_base = 0;
700 t -> id = 0;
701 t -> suspended = FALSE;
702 # ifdef RETRY_GET_THREAD_CONTEXT
703 t -> context_sp = NULL;
704 # endif
705 AO_store_release(&t->tm.in_use, FALSE);
706 } else
707 # endif
708 /* else */ {
709 DWORD id = ((GC_thread)t) -> id;
710 /* Cast away volatile qualifier, since we have lock. */
711 int hv = THREAD_TABLE_INDEX(id);
712 GC_thread p = GC_threads[hv];
713 GC_thread prev = NULL;
714
715 GC_ASSERT(I_HOLD_LOCK());
716 while (p != (GC_thread)t) {
717 prev = p;
718 p = p -> tm.next;
719 }
720 if (prev == 0) {
721 GC_threads[hv] = p -> tm.next;
722 } else {
723 GC_ASSERT(prev != &first_thread);
724 prev -> tm.next = p -> tm.next;
725 GC_dirty(prev);
726 }
727 }
728 }
729
730 /* Delete a thread from GC_threads. We assume it is there. */
731 /* (The code intentionally traps if it wasn't.) Assumes we */
732 /* hold the allocation lock unless GC_win32_dll_threads is set. */
733 /* If GC_win32_dll_threads is set then it should be called from */
734 /* the thread being deleted. It is also safe to delete the */
735 /* main thread (unless GC_win32_dll_threads). */
GC_delete_thread(DWORD id)736 STATIC void GC_delete_thread(DWORD id)
737 {
738 if (GC_win32_dll_threads) {
739 GC_vthread t = GC_lookup_thread_inner(id);
740
741 if (0 == t) {
742 WARN("Removing nonexistent thread, id = %" WARN_PRIdPTR "\n", id);
743 } else {
744 GC_delete_gc_thread_no_free(t);
745 }
746 } else {
747 int hv = THREAD_TABLE_INDEX(id);
748 GC_thread p = GC_threads[hv];
749 GC_thread prev = NULL;
750
751 GC_ASSERT(I_HOLD_LOCK());
752 while (p -> id != id) {
753 prev = p;
754 p = p -> tm.next;
755 }
756 # ifndef MSWINCE
757 CloseHandle(p->handle);
758 # endif
759 if (prev == 0) {
760 GC_threads[hv] = p -> tm.next;
761 } else {
762 GC_ASSERT(prev != &first_thread);
763 prev -> tm.next = p -> tm.next;
764 GC_dirty(prev);
765 }
766 if (EXPECT(p != &first_thread, TRUE)) {
767 GC_INTERNAL_FREE(p);
768 }
769 }
770 }
771
GC_allow_register_threads(void)772 GC_API void GC_CALL GC_allow_register_threads(void)
773 {
774 /* Check GC is initialized and the current thread is registered. */
775 GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId()) != 0);
776 # if !defined(GC_ALWAYS_MULTITHREADED) && !defined(PARALLEL_MARK) \
777 && !defined(GC_NO_THREADS_DISCOVERY)
778 /* GC_init() does not call GC_init_parallel() in this case. */
779 parallel_initialized = TRUE;
780 # endif
781 set_need_to_lock();
782 }
783
GC_register_my_thread(const struct GC_stack_base * sb)784 GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
785 {
786 GC_thread me;
787 DWORD thread_id = GetCurrentThreadId();
788 DCL_LOCK_STATE;
789
790 if (GC_need_to_lock == FALSE)
791 ABORT("Threads explicit registering is not previously enabled");
792
793 /* We lock here, since we want to wait for an ongoing GC. */
794 LOCK();
795 me = GC_lookup_thread_inner(thread_id);
796 if (me == 0) {
797 # ifdef GC_PTHREADS
798 me = GC_register_my_thread_inner(sb, thread_id);
799 me -> flags |= DETACHED;
800 /* Treat as detached, since we do not need to worry about */
801 /* pointer results. */
802 # else
803 GC_register_my_thread_inner(sb, thread_id);
804 # endif
805 UNLOCK();
806 return GC_SUCCESS;
807 } else
808 # ifdef GC_PTHREADS
809 /* else */ if ((me -> flags & FINISHED) != 0) {
810 GC_record_stack_base(me, sb);
811 me -> flags &= ~FINISHED; /* but not DETACHED */
812 # ifdef THREAD_LOCAL_ALLOC
813 GC_init_thread_local((GC_tlfs)(&me->tlfs));
814 # endif
815 UNLOCK();
816 return GC_SUCCESS;
817 } else
818 # endif
819 /* else */ {
820 UNLOCK();
821 return GC_DUPLICATE;
822 }
823 }
824
825 /* Similar to that in pthread_support.c. */
GC_wait_for_gc_completion(GC_bool wait_for_all)826 STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
827 {
828 GC_ASSERT(I_HOLD_LOCK());
829 if (GC_incremental && GC_collection_in_progress()) {
830 word old_gc_no = GC_gc_no;
831
832 /* Make sure that no part of our stack is still on the mark stack, */
833 /* since it's about to be unmapped. */
834 do {
835 ENTER_GC();
836 GC_in_thread_creation = TRUE;
837 GC_collect_a_little_inner(1);
838 GC_in_thread_creation = FALSE;
839 EXIT_GC();
840
841 UNLOCK();
842 Sleep(0); /* yield */
843 LOCK();
844 } while (GC_incremental && GC_collection_in_progress()
845 && (wait_for_all || old_gc_no == GC_gc_no));
846 }
847 }
848
GC_unregister_my_thread(void)849 GC_API int GC_CALL GC_unregister_my_thread(void)
850 {
851 DCL_LOCK_STATE;
852
853 # ifdef DEBUG_THREADS
854 GC_log_printf("Unregistering thread 0x%lx\n", (long)GetCurrentThreadId());
855 # endif
856
857 if (GC_win32_dll_threads) {
858 # if defined(THREAD_LOCAL_ALLOC)
859 /* Can't happen: see GC_use_threads_discovery(). */
860 GC_ASSERT(FALSE);
861 # else
862 /* FIXME: Should we just ignore this? */
863 GC_delete_thread(GetCurrentThreadId());
864 # endif
865 } else {
866 # if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
867 GC_thread me;
868 # endif
869 DWORD thread_id = GetCurrentThreadId();
870
871 LOCK();
872 GC_wait_for_gc_completion(FALSE);
873 # if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
874 me = GC_lookup_thread_inner(thread_id);
875 CHECK_LOOKUP_MY_THREAD(me);
876 GC_ASSERT(!KNOWN_FINISHED(me));
877 # endif
878 # if defined(THREAD_LOCAL_ALLOC)
879 GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
880 GC_destroy_thread_local(&(me->tlfs));
881 # endif
882 # ifdef GC_PTHREADS
883 if ((me -> flags & DETACHED) == 0) {
884 me -> flags |= FINISHED;
885 } else
886 # endif
887 /* else */ {
888 GC_delete_thread(thread_id);
889 }
890 # if defined(THREAD_LOCAL_ALLOC)
891 /* It is required to call remove_specific defined in specific.c. */
892 GC_remove_specific(GC_thread_key);
893 # endif
894 UNLOCK();
895 }
896 return GC_SUCCESS;
897 }
898
899 /* Wrapper for functions that are likely to block for an appreciable */
900 /* length of time. */
901
902 /* GC_do_blocking_inner() is nearly the same as in pthread_support.c */
GC_do_blocking_inner(ptr_t data,void * context GC_ATTR_UNUSED)903 GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
904 {
905 struct blocking_data * d = (struct blocking_data *) data;
906 DWORD thread_id = GetCurrentThreadId();
907 GC_thread me;
908 # ifdef IA64
909 ptr_t stack_ptr = GC_save_regs_in_stack();
910 # endif
911 DCL_LOCK_STATE;
912
913 LOCK();
914 me = GC_lookup_thread_inner(thread_id);
915 CHECK_LOOKUP_MY_THREAD(me);
916 GC_ASSERT(me -> thread_blocked_sp == NULL);
917 # ifdef IA64
918 me -> backing_store_ptr = stack_ptr;
919 # endif
920 me -> thread_blocked_sp = (ptr_t) &d; /* save approx. sp */
921 /* Save context here if we want to support precise stack marking */
922 UNLOCK();
923 d -> client_data = (d -> fn)(d -> client_data);
924 LOCK(); /* This will block if the world is stopped. */
925 # if defined(CPPCHECK)
926 GC_noop1((word)me->thread_blocked_sp);
927 # endif
928 me -> thread_blocked_sp = NULL;
929 UNLOCK();
930 }
931
932 /* GC_call_with_gc_active() has the opposite to GC_do_blocking() */
933 /* functionality. It might be called from a user function invoked by */
934 /* GC_do_blocking() to temporarily back allow calling any GC function */
935 /* and/or manipulating pointers to the garbage collected heap. */
GC_call_with_gc_active(GC_fn_type fn,void * client_data)936 GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
937 void * client_data)
938 {
939 struct GC_traced_stack_sect_s stacksect;
940 DWORD thread_id = GetCurrentThreadId();
941 GC_thread me;
942 DCL_LOCK_STATE;
943
944 LOCK(); /* This will block if the world is stopped. */
945 me = GC_lookup_thread_inner(thread_id);
946 CHECK_LOOKUP_MY_THREAD(me);
947 /* Adjust our stack base value (this could happen unless */
948 /* GC_get_stack_base() was used which returned GC_SUCCESS). */
949 GC_ASSERT(me -> stack_base != NULL);
950 if ((word)me->stack_base < (word)(&stacksect))
951 me -> stack_base = (ptr_t)(&stacksect);
952
953 if (me -> thread_blocked_sp == NULL) {
954 /* We are not inside GC_do_blocking() - do nothing more. */
955 UNLOCK();
956 client_data = fn(client_data);
957 /* Prevent treating the above as a tail call. */
958 GC_noop1(COVERT_DATAFLOW(&stacksect));
959 return client_data; /* result */
960 }
961
962 /* Setup new "stack section". */
963 stacksect.saved_stack_ptr = me -> thread_blocked_sp;
964 # ifdef IA64
965 /* This is the same as in GC_call_with_stack_base(). */
966 stacksect.backing_store_end = GC_save_regs_in_stack();
967 /* Unnecessarily flushes register stack, */
968 /* but that probably doesn't hurt. */
969 stacksect.saved_backing_store_ptr = me -> backing_store_ptr;
970 # endif
971 stacksect.prev = me -> traced_stack_sect;
972 me -> thread_blocked_sp = NULL;
973 me -> traced_stack_sect = &stacksect;
974
975 UNLOCK();
976 client_data = fn(client_data);
977 GC_ASSERT(me -> thread_blocked_sp == NULL);
978 GC_ASSERT(me -> traced_stack_sect == &stacksect);
979
980 /* Restore original "stack section". */
981 LOCK();
982 # if defined(CPPCHECK)
983 GC_noop1((word)me->traced_stack_sect);
984 # endif
985 me -> traced_stack_sect = stacksect.prev;
986 # ifdef IA64
987 me -> backing_store_ptr = stacksect.saved_backing_store_ptr;
988 # endif
989 me -> thread_blocked_sp = stacksect.saved_stack_ptr;
990 UNLOCK();
991
992 return client_data; /* result */
993 }
994
995 #ifdef GC_PTHREADS
996
997 /* A quick-and-dirty cache of the mapping between pthread_t */
998 /* and win32 thread id. */
999 # define PTHREAD_MAP_SIZE 512
1000 DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE] = {0};
1001 # define PTHREAD_MAP_INDEX(pthread_id) \
1002 ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
1003 /* It appears pthread_t is really a pointer type ... */
1004 # define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
1005 (void)(GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)] = (win32_id))
1006 # define GET_PTHREAD_MAP_CACHE(pthread_id) \
1007 GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)]
1008
1009 /* Return a GC_thread corresponding to a given pthread_t. */
1010 /* Returns 0 if it's not there. */
1011 /* We assume that this is only called for pthread ids that */
1012 /* have not yet terminated or are still joinable, and */
1013 /* cannot be concurrently terminated. */
1014 /* Assumes we do NOT hold the allocation lock. */
GC_lookup_pthread(pthread_t id)1015 STATIC GC_thread GC_lookup_pthread(pthread_t id)
1016 {
1017 # ifndef GC_NO_THREADS_DISCOVERY
1018 if (GC_win32_dll_threads) {
1019 int i;
1020 LONG my_max = GC_get_max_thread_index();
1021
1022 for (i = 0; i <= my_max &&
1023 (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
1024 || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
1025 /* Must still be in_use, since nobody else can */
1026 /* store our thread_id. */
1027 i++) {
1028 /* empty */
1029 }
1030 return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
1031 } else
1032 # endif
1033 /* else */ {
1034 /* We first try the cache. If that fails, we use a very slow */
1035 /* approach. */
1036 DWORD win32_id = GET_PTHREAD_MAP_CACHE(id);
1037 int hv_guess = THREAD_TABLE_INDEX(win32_id);
1038 int hv;
1039 GC_thread p;
1040 DCL_LOCK_STATE;
1041
1042 LOCK();
1043 for (p = GC_threads[hv_guess]; 0 != p; p = p -> tm.next) {
1044 if (THREAD_EQUAL(p -> pthread_id, id))
1045 goto foundit;
1046 }
1047 for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
1048 for (p = GC_threads[hv]; 0 != p; p = p -> tm.next) {
1049 if (THREAD_EQUAL(p -> pthread_id, id))
1050 goto foundit;
1051 }
1052 }
1053 p = 0;
1054 foundit:
1055 UNLOCK();
1056 return p;
1057 }
1058 }
1059
1060 #endif /* GC_PTHREADS */
1061
1062 #ifdef CAN_HANDLE_FORK
1063 /* Similar to that in pthread_support.c but also rehashes the table */
1064 /* since hash map key (thread_id) differs from that in the parent. */
GC_remove_all_threads_but_me(void)1065 STATIC void GC_remove_all_threads_but_me(void)
1066 {
1067 int hv;
1068 GC_thread me = NULL;
1069 DWORD thread_id;
1070 pthread_t pthread_id = pthread_self(); /* same as in parent */
1071
1072 GC_ASSERT(!GC_win32_dll_threads);
1073 for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
1074 GC_thread p, next;
1075
1076 for (p = GC_threads[hv]; 0 != p; p = next) {
1077 next = p -> tm.next;
1078 if (THREAD_EQUAL(p -> pthread_id, pthread_id)
1079 && me == NULL) { /* ignore dead threads with the same id */
1080 me = p;
1081 p -> tm.next = 0;
1082 } else {
1083 # ifdef THREAD_LOCAL_ALLOC
1084 if ((p -> flags & FINISHED) == 0) {
1085 /* Cannot call GC_destroy_thread_local here (see the */
1086 /* corresponding comment in pthread_support.c). */
1087 GC_remove_specific_after_fork(GC_thread_key, p -> pthread_id);
1088 }
1089 # endif
1090 if (&first_thread != p)
1091 GC_INTERNAL_FREE(p);
1092 }
1093 }
1094 GC_threads[hv] = NULL;
1095 }
1096
1097 /* Put "me" back to GC_threads. */
1098 GC_ASSERT(me != NULL);
1099 thread_id = GetCurrentThreadId(); /* differs from that in parent */
1100 GC_threads[THREAD_TABLE_INDEX(thread_id)] = me;
1101
1102 /* Update Win32 thread Id and handle. */
1103 me -> id = thread_id;
1104 # ifndef MSWINCE
1105 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
1106 GetCurrentProcess(), (HANDLE *)&me->handle,
1107 0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
1108 DUPLICATE_SAME_ACCESS))
1109 ABORT("DuplicateHandle failed");
1110 # endif
1111
1112 # if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
1113 /* For Cygwin, we need to re-assign thread-local pointer to */
1114 /* 'tlfs' (it is OK to call GC_destroy_thread_local and */
1115 /* GC_free_internal before this action). */
1116 if (GC_setspecific(GC_thread_key, &me->tlfs) != 0)
1117 ABORT("GC_setspecific failed (in child)");
1118 # endif
1119 }
1120
fork_prepare_proc(void)1121 static void fork_prepare_proc(void)
1122 {
1123 LOCK();
1124 # ifdef PARALLEL_MARK
1125 if (GC_parallel)
1126 GC_wait_for_reclaim();
1127 # endif
1128 GC_wait_for_gc_completion(TRUE);
1129 # ifdef PARALLEL_MARK
1130 if (GC_parallel)
1131 GC_acquire_mark_lock();
1132 # endif
1133 }
1134
fork_parent_proc(void)1135 static void fork_parent_proc(void)
1136 {
1137 # ifdef PARALLEL_MARK
1138 if (GC_parallel)
1139 GC_release_mark_lock();
1140 # endif
1141 UNLOCK();
1142 }
1143
fork_child_proc(void)1144 static void fork_child_proc(void)
1145 {
1146 # ifdef PARALLEL_MARK
1147 if (GC_parallel) {
1148 GC_release_mark_lock();
1149 GC_parallel = FALSE; /* or GC_markers_m1 = 0 */
1150 /* Turn off parallel marking in the child, since we are */
1151 /* probably just going to exec, and we would have to */
1152 /* restart mark threads. */
1153 }
1154 # endif
1155 GC_remove_all_threads_but_me();
1156 UNLOCK();
1157 }
1158
1159 /* Routines for fork handling by client (no-op if pthread_atfork works). */
GC_atfork_prepare(void)1160 GC_API void GC_CALL GC_atfork_prepare(void)
1161 {
1162 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
1163 if (GC_handle_fork <= 0)
1164 fork_prepare_proc();
1165 }
1166
GC_atfork_parent(void)1167 GC_API void GC_CALL GC_atfork_parent(void)
1168 {
1169 if (GC_handle_fork <= 0)
1170 fork_parent_proc();
1171 }
1172
GC_atfork_child(void)1173 GC_API void GC_CALL GC_atfork_child(void)
1174 {
1175 if (GC_handle_fork <= 0)
1176 fork_child_proc();
1177 }
1178 #endif /* CAN_HANDLE_FORK */
1179
GC_push_thread_structures(void)1180 void GC_push_thread_structures(void)
1181 {
1182 GC_ASSERT(I_HOLD_LOCK());
1183 # ifndef GC_NO_THREADS_DISCOVERY
1184 if (GC_win32_dll_threads) {
1185 /* Unlike the other threads implementations, the thread table */
1186 /* here contains no pointers to the collectible heap (note also */
1187 /* that GC_PTHREADS is incompatible with DllMain-based thread */
1188 /* registration). Thus we have no private structures we need */
1189 /* to preserve. */
1190 } else
1191 # endif
1192 /* else */ {
1193 GC_PUSH_ALL_SYM(GC_threads);
1194 }
1195 # if defined(THREAD_LOCAL_ALLOC)
1196 GC_PUSH_ALL_SYM(GC_thread_key);
1197 /* Just in case we ever use our own TLS implementation. */
1198 # endif
1199 }
1200
1201 #ifdef WOW64_THREAD_CONTEXT_WORKAROUND
1202 # ifndef CONTEXT_EXCEPTION_ACTIVE
1203 # define CONTEXT_EXCEPTION_ACTIVE 0x08000000
1204 # define CONTEXT_EXCEPTION_REQUEST 0x40000000
1205 # define CONTEXT_EXCEPTION_REPORTING 0x80000000
1206 # endif
1207 static BOOL isWow64; /* Is running 32-bit code on Win64? */
1208 # define GET_THREAD_CONTEXT_FLAGS (isWow64 \
1209 ? CONTEXT_INTEGER | CONTEXT_CONTROL \
1210 | CONTEXT_EXCEPTION_REQUEST | CONTEXT_SEGMENTS \
1211 : CONTEXT_INTEGER | CONTEXT_CONTROL)
1212 #else
1213 # define GET_THREAD_CONTEXT_FLAGS (CONTEXT_INTEGER | CONTEXT_CONTROL)
1214 #endif /* !WOW64_THREAD_CONTEXT_WORKAROUND */
1215
1216 /* Suspend the given thread, if it's still active. */
GC_suspend(GC_thread t)1217 STATIC void GC_suspend(GC_thread t)
1218 {
1219 # ifndef MSWINCE
1220 DWORD exitCode;
1221 # endif
1222 # ifdef RETRY_GET_THREAD_CONTEXT
1223 int retry_cnt = 0;
1224 # define MAX_SUSPEND_THREAD_RETRIES (1000 * 1000)
1225 # endif
1226
1227 UNPROTECT_THREAD(t);
1228 GC_acquire_dirty_lock();
1229
1230 # ifdef MSWINCE
1231 /* SuspendThread() will fail if thread is running kernel code. */
1232 while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) {
1233 GC_release_dirty_lock();
1234 Sleep(10); /* in millis */
1235 GC_acquire_dirty_lock();
1236 }
1237 # elif defined(RETRY_GET_THREAD_CONTEXT)
1238 for (;;) {
1239 /* Apparently the Windows 95 GetOpenFileName call creates */
1240 /* a thread that does not properly get cleaned up, and */
1241 /* SuspendThread on its descriptor may provoke a crash. */
1242 /* This reduces the probability of that event, though it still */
1243 /* appears there is a race here. */
1244 if (GetExitCodeThread(t -> handle, &exitCode)
1245 && exitCode != STILL_ACTIVE) {
1246 GC_release_dirty_lock();
1247 # ifdef GC_PTHREADS
1248 t -> stack_base = 0; /* prevent stack from being pushed */
1249 # else
1250 /* This breaks pthread_join on Cygwin, which is guaranteed to */
1251 /* only see user threads. */
1252 GC_ASSERT(GC_win32_dll_threads);
1253 GC_delete_gc_thread_no_free(t);
1254 # endif
1255 return;
1256 }
1257
1258 if (SuspendThread(t->handle) != (DWORD)-1) {
1259 CONTEXT context;
1260
1261 context.ContextFlags = GET_THREAD_CONTEXT_FLAGS;
1262 if (GetThreadContext(t->handle, &context)) {
1263 /* TODO: WoW64 extra workaround: if CONTEXT_EXCEPTION_ACTIVE */
1264 /* then Sleep(1) and retry. */
1265 t->context_sp = copy_ptr_regs(t->context_regs, &context);
1266 break; /* success; the context pointer registers are saved */
1267 }
1268
1269 /* Resume the thread, try to suspend it in a better location. */
1270 if (ResumeThread(t->handle) == (DWORD)-1)
1271 ABORT("ResumeThread failed in suspend loop");
1272 }
1273 if (retry_cnt > 1) {
1274 GC_release_dirty_lock();
1275 Sleep(0); /* yield */
1276 GC_acquire_dirty_lock();
1277 }
1278 if (++retry_cnt >= MAX_SUSPEND_THREAD_RETRIES)
1279 ABORT("SuspendThread loop failed"); /* something must be wrong */
1280 }
1281 # else
1282 if (GetExitCodeThread(t -> handle, &exitCode)
1283 && exitCode != STILL_ACTIVE) {
1284 GC_release_dirty_lock();
1285 # ifdef GC_PTHREADS
1286 t -> stack_base = 0; /* prevent stack from being pushed */
1287 # else
1288 GC_ASSERT(GC_win32_dll_threads);
1289 GC_delete_gc_thread_no_free(t);
1290 # endif
1291 return;
1292 }
1293 if (SuspendThread(t -> handle) == (DWORD)-1)
1294 ABORT("SuspendThread failed");
1295 # endif
1296 t -> suspended = (unsigned char)TRUE;
1297 GC_release_dirty_lock();
1298 if (GC_on_thread_event)
1299 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, THREAD_HANDLE(t));
1300 }
1301
1302 #if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
1303 GC_INNER GC_bool GC_write_disabled = FALSE;
1304 /* TRUE only if GC_stop_world() acquired GC_write_cs. */
1305 #endif
1306
GC_stop_world(void)1307 GC_INNER void GC_stop_world(void)
1308 {
1309 DWORD thread_id = GetCurrentThreadId();
1310
1311 if (!GC_thr_initialized)
1312 ABORT("GC_stop_world() called before GC_thr_init()");
1313 GC_ASSERT(I_HOLD_LOCK());
1314
1315 /* This code is the same as in pthread_stop_world.c */
1316 # ifdef PARALLEL_MARK
1317 if (GC_parallel) {
1318 GC_acquire_mark_lock();
1319 GC_ASSERT(GC_fl_builder_count == 0);
1320 /* We should have previously waited for it to become zero. */
1321 }
1322 # endif /* PARALLEL_MARK */
1323
1324 # if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
1325 GC_please_stop = TRUE;
1326 # endif
1327 # ifndef CYGWIN32
1328 # ifndef MSWIN_XBOX1
1329 GC_ASSERT(!GC_write_disabled);
1330 # endif
1331 EnterCriticalSection(&GC_write_cs);
1332 # endif
1333 # if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
1334 /* It's not allowed to call GC_printf() (and friends) here down to */
1335 /* LeaveCriticalSection (same applies recursively to GC_suspend, */
1336 /* GC_delete_gc_thread_no_free, GC_get_max_thread_index, GC_size */
1337 /* and GC_remove_protection). */
1338 GC_write_disabled = TRUE;
1339 # endif
1340 # ifndef GC_NO_THREADS_DISCOVERY
1341 if (GC_win32_dll_threads) {
1342 int i;
1343 int my_max;
1344 /* Any threads being created during this loop will end up setting */
1345 /* GC_attached_thread when they start. This will force marking */
1346 /* to restart. This is not ideal, but hopefully correct. */
1347 AO_store(&GC_attached_thread, FALSE);
1348 my_max = (int)GC_get_max_thread_index();
1349 for (i = 0; i <= my_max; i++) {
1350 GC_vthread t = dll_thread_table + i;
1351 if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
1352 && t -> id != thread_id) {
1353 GC_suspend((GC_thread)t);
1354 }
1355 }
1356 } else
1357 # endif
1358 /* else */ {
1359 GC_thread t;
1360 int i;
1361
1362 for (i = 0; i < THREAD_TABLE_SZ; i++) {
1363 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1364 if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
1365 && !KNOWN_FINISHED(t) && t -> id != thread_id) {
1366 GC_suspend(t);
1367 }
1368 }
1369 }
1370 }
1371 # if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
1372 GC_write_disabled = FALSE;
1373 # endif
1374 # ifndef CYGWIN32
1375 LeaveCriticalSection(&GC_write_cs);
1376 # endif
1377 # ifdef PARALLEL_MARK
1378 if (GC_parallel)
1379 GC_release_mark_lock();
1380 # endif
1381 }
1382
GC_start_world(void)1383 GC_INNER void GC_start_world(void)
1384 {
1385 # ifdef GC_ASSERTIONS
1386 DWORD thread_id = GetCurrentThreadId();
1387 # endif
1388
1389 GC_ASSERT(I_HOLD_LOCK());
1390 if (GC_win32_dll_threads) {
1391 LONG my_max = GC_get_max_thread_index();
1392 int i;
1393
1394 for (i = 0; i <= my_max; i++) {
1395 GC_thread t = (GC_thread)(dll_thread_table + i);
1396 if (t -> suspended) {
1397 GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
1398 if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
1399 ABORT("ResumeThread failed");
1400 t -> suspended = FALSE;
1401 if (GC_on_thread_event)
1402 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
1403 }
1404 }
1405 } else {
1406 GC_thread t;
1407 int i;
1408
1409 for (i = 0; i < THREAD_TABLE_SZ; i++) {
1410 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1411 if (t -> suspended) {
1412 GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
1413 if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
1414 ABORT("ResumeThread failed");
1415 UNPROTECT_THREAD(t);
1416 t -> suspended = FALSE;
1417 if (GC_on_thread_event)
1418 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
1419 }
1420 }
1421 }
1422 }
1423 # if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
1424 GC_please_stop = FALSE;
1425 # endif
1426 }
1427
1428 #ifdef MSWINCE
1429 /* The VirtualQuery calls below won't work properly on some old WinCE */
1430 /* versions, but since each stack is restricted to an aligned 64 KiB */
1431 /* region of virtual memory we can just take the next lowest multiple */
1432 /* of 64 KiB. The result of this macro must not be used as its */
1433 /* argument later and must not be used as the lower bound for sp */
1434 /* check (since the stack may be bigger than 64 KiB). */
1435 # define GC_wince_evaluate_stack_min(s) \
1436 (ptr_t)(((word)(s) - 1) & ~(word)0xFFFF)
1437 #elif defined(GC_ASSERTIONS)
1438 # define GC_dont_query_stack_min FALSE
1439 #endif
1440
1441 /* A cache holding the results of the recent VirtualQuery call. */
1442 /* Protected by the allocation lock. */
1443 static ptr_t last_address = 0;
1444 static MEMORY_BASIC_INFORMATION last_info;
1445
1446 /* Probe stack memory region (starting at "s") to find out its */
1447 /* lowest address (i.e. stack top). */
1448 /* S must be a mapped address inside the region, NOT the first */
1449 /* unmapped address. */
GC_get_stack_min(ptr_t s)1450 STATIC ptr_t GC_get_stack_min(ptr_t s)
1451 {
1452 ptr_t bottom;
1453
1454 GC_ASSERT(I_HOLD_LOCK());
1455 if (s != last_address) {
1456 VirtualQuery(s, &last_info, sizeof(last_info));
1457 last_address = s;
1458 }
1459 do {
1460 bottom = (ptr_t)last_info.BaseAddress;
1461 VirtualQuery(bottom - 1, &last_info, sizeof(last_info));
1462 last_address = bottom - 1;
1463 } while ((last_info.Protect & PAGE_READWRITE)
1464 && !(last_info.Protect & PAGE_GUARD));
1465 return(bottom);
1466 }
1467
1468 /* Return true if the page at s has protections appropriate */
1469 /* for a stack page. */
may_be_in_stack(ptr_t s)1470 static GC_bool may_be_in_stack(ptr_t s)
1471 {
1472 GC_ASSERT(I_HOLD_LOCK());
1473 if (s != last_address) {
1474 VirtualQuery(s, &last_info, sizeof(last_info));
1475 last_address = s;
1476 }
1477 return (last_info.Protect & PAGE_READWRITE)
1478 && !(last_info.Protect & PAGE_GUARD);
1479 }
1480
1481 /* Copy all registers that might point into the heap. Frame */
1482 /* pointer registers are included in case client code was */
1483 /* compiled with the 'omit frame pointer' optimization. */
1484 /* The context register values are stored to regs argument */
1485 /* which is expected to be of PUSHED_REGS_COUNT length exactly. */
1486 /* The functions returns the context stack pointer value. */
copy_ptr_regs(word * regs,const CONTEXT * pcontext)1487 static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) {
1488 ptr_t sp;
1489 int cnt = 0;
1490 # define context (*pcontext)
1491 # define PUSH1(reg) (regs[cnt++] = (word)pcontext->reg)
1492 # define PUSH2(r1,r2) (PUSH1(r1), PUSH1(r2))
1493 # define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4))
1494 # if defined(I386)
1495 # ifdef WOW64_THREAD_CONTEXT_WORKAROUND
1496 PUSH2(ContextFlags, SegFs); /* cannot contain pointers */
1497 # endif
1498 PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
1499 sp = (ptr_t)context.Esp;
1500 # elif defined(X86_64)
1501 PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
1502 PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
1503 sp = (ptr_t)context.Rsp;
1504 # elif defined(ARM32)
1505 PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11);
1506 PUSH1(R12);
1507 sp = (ptr_t)context.Sp;
1508 # elif defined(AARCH64)
1509 PUSH4(X0,X1,X2,X3),PUSH4(X4,X5,X6,X7),PUSH4(X8,X9,X10,X11);
1510 PUSH4(X12,X13,X14,X15),PUSH4(X16,X17,X18,X19),PUSH4(X20,X21,X22,X23);
1511 PUSH4(X24,X25,X26,X27),PUSH1(X28);
1512 PUSH1(Lr);
1513 sp = (ptr_t)context.Sp;
1514 # elif defined(SHx)
1515 PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
1516 PUSH2(R12,R13), PUSH1(R14);
1517 sp = (ptr_t)context.R15;
1518 # elif defined(MIPS)
1519 PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
1520 PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
1521 PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
1522 PUSH4(IntT9,IntK0,IntK1,IntS8);
1523 sp = (ptr_t)context.IntSp;
1524 # elif defined(PPC)
1525 PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
1526 PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
1527 PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
1528 PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
1529 sp = (ptr_t)context.Gpr1;
1530 # elif defined(ALPHA)
1531 PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
1532 PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
1533 PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
1534 PUSH4(IntT10,IntT11,IntT12,IntAt);
1535 sp = (ptr_t)context.IntSp;
1536 # elif defined(CPPCHECK)
1537 sp = (ptr_t)(word)cnt; /* to workaround "cnt not used" false positive */
1538 # else
1539 # error Architecture is not supported
1540 # endif
1541 # undef context
1542 GC_ASSERT(cnt == PUSHED_REGS_COUNT);
1543 return sp;
1544 }
1545
GC_push_stack_for(GC_thread thread,DWORD me)1546 STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
1547 {
1548 ptr_t sp, stack_min;
1549
1550 struct GC_traced_stack_sect_s *traced_stack_sect =
1551 thread -> traced_stack_sect;
1552 if (thread -> id == me) {
1553 GC_ASSERT(thread -> thread_blocked_sp == NULL);
1554 sp = GC_approx_sp();
1555 } else if ((sp = thread -> thread_blocked_sp) == NULL) {
1556 /* Use saved sp value for blocked threads. */
1557 int i = 0;
1558 # ifdef RETRY_GET_THREAD_CONTEXT
1559 /* We cache context when suspending the thread since it may */
1560 /* require looping. */
1561 word *regs = thread->context_regs;
1562
1563 if (thread->suspended) {
1564 sp = thread->context_sp;
1565 } else
1566 # else
1567 word regs[PUSHED_REGS_COUNT];
1568 # endif
1569
1570 /* else */ {
1571 CONTEXT context;
1572
1573 /* For unblocked threads call GetThreadContext(). */
1574 context.ContextFlags = GET_THREAD_CONTEXT_FLAGS;
1575 if (GetThreadContext(THREAD_HANDLE(thread), &context)) {
1576 sp = copy_ptr_regs(regs, &context);
1577 } else {
1578 # ifdef RETRY_GET_THREAD_CONTEXT
1579 /* At least, try to use the stale context if saved. */
1580 sp = thread->context_sp;
1581 if (NULL == sp) {
1582 /* Skip the current thread, anyway its stack will */
1583 /* be pushed when the world is stopped. */
1584 return 0;
1585 }
1586 # else
1587 ABORT("GetThreadContext failed");
1588 # endif
1589 }
1590 }
1591
1592 # ifdef WOW64_THREAD_CONTEXT_WORKAROUND
1593 i += 2; /* skip ContextFlags and SegFs */
1594 # endif
1595 for (; i < PUSHED_REGS_COUNT; i++)
1596 GC_push_one(regs[i]);
1597
1598 # ifdef WOW64_THREAD_CONTEXT_WORKAROUND
1599 /* WoW64 workaround. */
1600 if (isWow64) {
1601 DWORD ContextFlags = (DWORD)regs[0];
1602 WORD SegFs = (WORD)regs[1];
1603
1604 if ((ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0
1605 && (ContextFlags & (CONTEXT_EXCEPTION_ACTIVE
1606 /* | CONTEXT_SERVICE_ACTIVE */)) != 0) {
1607 LDT_ENTRY selector;
1608 PNT_TIB tib;
1609
1610 if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), SegFs, &selector))
1611 ABORT("GetThreadSelectorEntry failed");
1612 tib = (PNT_TIB)(selector.BaseLow
1613 | (selector.HighWord.Bits.BaseMid << 16)
1614 | (selector.HighWord.Bits.BaseHi << 24));
1615 # ifdef DEBUG_THREADS
1616 GC_log_printf("TIB stack limit/base: %p .. %p\n",
1617 (void *)tib->StackLimit, (void *)tib->StackBase);
1618 # endif
1619 GC_ASSERT(!((word)thread->stack_base
1620 COOLER_THAN (word)tib->StackBase));
1621
1622 /* GetThreadContext() might return stale register values, */
1623 /* so we scan the entire stack region (down to the stack */
1624 /* limit). There is no 100% guarantee that all the */
1625 /* registers are pushed but we do our best (the proper */
1626 /* solution would be to fix it inside Windows OS). */
1627 sp = (ptr_t)tib->StackLimit;
1628 } /* else */
1629 # ifdef DEBUG_THREADS
1630 else {
1631 static GC_bool logged;
1632 if (!logged
1633 && (ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) {
1634 GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n");
1635 logged = TRUE;
1636 }
1637 }
1638 # endif
1639 }
1640 # endif /* WOW64_THREAD_CONTEXT_WORKAROUND */
1641 } /* ! current thread */
1642
1643 /* Set stack_min to the lowest address in the thread stack, */
1644 /* or to an address in the thread stack no larger than sp, */
1645 /* taking advantage of the old value to avoid slow traversals */
1646 /* of large stacks. */
1647 if (thread -> last_stack_min == ADDR_LIMIT) {
1648 # ifdef MSWINCE
1649 if (GC_dont_query_stack_min) {
1650 stack_min = GC_wince_evaluate_stack_min(traced_stack_sect != NULL ?
1651 (ptr_t)traced_stack_sect : thread -> stack_base);
1652 /* Keep last_stack_min value unmodified. */
1653 } else
1654 # endif
1655 /* else */ {
1656 stack_min = GC_get_stack_min(traced_stack_sect != NULL ?
1657 (ptr_t)traced_stack_sect : thread -> stack_base);
1658 UNPROTECT_THREAD(thread);
1659 thread -> last_stack_min = stack_min;
1660 }
1661 } else {
1662 /* First, adjust the latest known minimum stack address if we */
1663 /* are inside GC_call_with_gc_active(). */
1664 if (traced_stack_sect != NULL &&
1665 (word)thread->last_stack_min > (word)traced_stack_sect) {
1666 UNPROTECT_THREAD(thread);
1667 thread -> last_stack_min = (ptr_t)traced_stack_sect;
1668 }
1669
1670 if ((word)sp < (word)thread->stack_base
1671 && (word)sp >= (word)thread->last_stack_min) {
1672 stack_min = sp;
1673 } else {
1674 /* In the current thread it is always safe to use sp value. */
1675 if (may_be_in_stack(thread -> id == me &&
1676 (word)sp < (word)thread->last_stack_min ?
1677 sp : thread -> last_stack_min)) {
1678 stack_min = (ptr_t)last_info.BaseAddress;
1679 /* Do not probe rest of the stack if sp is correct. */
1680 if ((word)sp < (word)stack_min
1681 || (word)sp >= (word)thread->stack_base)
1682 stack_min = GC_get_stack_min(thread -> last_stack_min);
1683 } else {
1684 /* Stack shrunk? Is this possible? */
1685 stack_min = GC_get_stack_min(thread -> stack_base);
1686 }
1687 UNPROTECT_THREAD(thread);
1688 thread -> last_stack_min = stack_min;
1689 }
1690 }
1691
1692 GC_ASSERT(GC_dont_query_stack_min
1693 || stack_min == GC_get_stack_min(thread -> stack_base)
1694 || ((word)sp >= (word)stack_min
1695 && (word)stack_min < (word)thread->stack_base
1696 && (word)stack_min
1697 > (word)GC_get_stack_min(thread -> stack_base)));
1698
1699 if ((word)sp >= (word)stack_min && (word)sp < (word)thread->stack_base) {
1700 # ifdef DEBUG_THREADS
1701 GC_log_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
1702 (int)thread->id, (void *)sp, (void *)thread->stack_base,
1703 (int)me);
1704 # endif
1705 GC_push_all_stack_sections(sp, thread->stack_base, traced_stack_sect);
1706 } else {
1707 /* If not current thread then it is possible for sp to point to */
1708 /* the guarded (untouched yet) page just below the current */
1709 /* stack_min of the thread. */
1710 if (thread -> id == me || (word)sp >= (word)thread->stack_base
1711 || (word)(sp + GC_page_size) < (word)stack_min)
1712 WARN("Thread stack pointer %p out of range, pushing everything\n",
1713 sp);
1714 # ifdef DEBUG_THREADS
1715 GC_log_printf("Pushing stack for 0x%x from (min) %p to %p from 0x%x\n",
1716 (int)thread->id, (void *)stack_min,
1717 (void *)thread->stack_base, (int)me);
1718 # endif
1719 /* Push everything - ignore "traced stack section" data. */
1720 GC_push_all_stack(stack_min, thread->stack_base);
1721 }
1722 return thread->stack_base - sp; /* stack grows down */
1723 }
1724
1725 /* We hold allocation lock. Should do exactly the right thing if the */
1726 /* world is stopped. Should not fail if it isn't. */
GC_push_all_stacks(void)1727 GC_INNER void GC_push_all_stacks(void)
1728 {
1729 DWORD thread_id = GetCurrentThreadId();
1730 GC_bool found_me = FALSE;
1731 # ifndef SMALL_CONFIG
1732 unsigned nthreads = 0;
1733 # endif
1734 word total_size = 0;
1735 # ifndef GC_NO_THREADS_DISCOVERY
1736 if (GC_win32_dll_threads) {
1737 int i;
1738 LONG my_max = GC_get_max_thread_index();
1739
1740 for (i = 0; i <= my_max; i++) {
1741 GC_thread t = (GC_thread)(dll_thread_table + i);
1742 if (t -> tm.in_use && t -> stack_base) {
1743 # ifndef SMALL_CONFIG
1744 ++nthreads;
1745 # endif
1746 total_size += GC_push_stack_for(t, thread_id);
1747 if (t -> id == thread_id) found_me = TRUE;
1748 }
1749 }
1750 } else
1751 # endif
1752 /* else */ {
1753 int i;
1754 for (i = 0; i < THREAD_TABLE_SZ; i++) {
1755 GC_thread t;
1756 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1757 if (!KNOWN_FINISHED(t) && t -> stack_base) {
1758 # ifndef SMALL_CONFIG
1759 ++nthreads;
1760 # endif
1761 total_size += GC_push_stack_for(t, thread_id);
1762 if (t -> id == thread_id) found_me = TRUE;
1763 }
1764 }
1765 }
1766 }
1767 # ifndef SMALL_CONFIG
1768 GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks%s\n", nthreads,
1769 GC_win32_dll_threads ?
1770 " based on DllMain thread tracking" : "");
1771 # endif
1772 if (!found_me && !GC_in_thread_creation)
1773 ABORT("Collecting from unknown thread");
1774 GC_total_stacksize = total_size;
1775 }
1776
1777 #ifdef PARALLEL_MARK
1778
1779 # ifndef MAX_MARKERS
1780 # define MAX_MARKERS 16
1781 # endif
1782
1783 static ptr_t marker_sp[MAX_MARKERS - 1]; /* The cold end of the stack */
1784 /* for markers. */
1785 # ifdef IA64
1786 static ptr_t marker_bsp[MAX_MARKERS - 1];
1787 # endif
1788
1789 static ptr_t marker_last_stack_min[MAX_MARKERS - 1];
1790 /* Last known minimum (hottest) address */
1791 /* in stack (or ADDR_LIMIT if unset) */
1792 /* for markers. */
1793
1794 #endif /* PARALLEL_MARK */
1795
1796 /* Find stack with the lowest address which overlaps the */
1797 /* interval [start, limit). */
1798 /* Return stack bounds in *lo and *hi. If no such stack */
1799 /* is found, both *hi and *lo will be set to an address */
1800 /* higher than limit. */
GC_get_next_stack(char * start,char * limit,char ** lo,char ** hi)1801 GC_INNER void GC_get_next_stack(char *start, char *limit,
1802 char **lo, char **hi)
1803 {
1804 int i;
1805 char * current_min = ADDR_LIMIT; /* Least in-range stack base */
1806 ptr_t *plast_stack_min = NULL; /* Address of last_stack_min */
1807 /* field for thread corresponding */
1808 /* to current_min. */
1809 GC_thread thread = NULL; /* Either NULL or points to the */
1810 /* thread's hash table entry */
1811 /* containing *plast_stack_min. */
1812
1813 /* First set current_min, ignoring limit. */
1814 if (GC_win32_dll_threads) {
1815 LONG my_max = GC_get_max_thread_index();
1816
1817 for (i = 0; i <= my_max; i++) {
1818 ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
1819
1820 if ((word)s > (word)start && (word)s < (word)current_min) {
1821 /* Update address of last_stack_min. */
1822 plast_stack_min = (ptr_t * /* no volatile */)
1823 &dll_thread_table[i].last_stack_min;
1824 current_min = s;
1825 # if defined(CPPCHECK)
1826 /* To avoid a warning that thread is always null. */
1827 thread = (GC_thread)&dll_thread_table[i];
1828 # endif
1829 }
1830 }
1831 } else {
1832 for (i = 0; i < THREAD_TABLE_SZ; i++) {
1833 GC_thread t;
1834
1835 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1836 ptr_t s = t -> stack_base;
1837
1838 if ((word)s > (word)start && (word)s < (word)current_min) {
1839 /* Update address of last_stack_min. */
1840 plast_stack_min = &t -> last_stack_min;
1841 thread = t; /* Remember current thread to unprotect. */
1842 current_min = s;
1843 }
1844 }
1845 }
1846 # ifdef PARALLEL_MARK
1847 for (i = 0; i < GC_markers_m1; ++i) {
1848 ptr_t s = marker_sp[i];
1849 # ifdef IA64
1850 /* FIXME: not implemented */
1851 # endif
1852 if ((word)s > (word)start && (word)s < (word)current_min) {
1853 GC_ASSERT(marker_last_stack_min[i] != NULL);
1854 plast_stack_min = &marker_last_stack_min[i];
1855 current_min = s;
1856 thread = NULL; /* Not a thread's hash table entry. */
1857 }
1858 }
1859 # endif
1860 }
1861
1862 *hi = current_min;
1863 if (current_min == ADDR_LIMIT) {
1864 *lo = ADDR_LIMIT;
1865 return;
1866 }
1867
1868 GC_ASSERT((word)current_min > (word)start && plast_stack_min != NULL);
1869 # ifdef MSWINCE
1870 if (GC_dont_query_stack_min) {
1871 *lo = GC_wince_evaluate_stack_min(current_min);
1872 /* Keep last_stack_min value unmodified. */
1873 return;
1874 }
1875 # endif
1876
1877 if ((word)current_min > (word)limit && !may_be_in_stack(limit)) {
1878 /* Skip the rest since the memory region at limit address is */
1879 /* not a stack (so the lowest address of the found stack would */
1880 /* be above the limit value anyway). */
1881 *lo = ADDR_LIMIT;
1882 return;
1883 }
1884
1885 /* Get the minimum address of the found stack by probing its memory */
1886 /* region starting from the recent known minimum (if set). */
1887 if (*plast_stack_min == ADDR_LIMIT
1888 || !may_be_in_stack(*plast_stack_min)) {
1889 /* Unsafe to start from last_stack_min value. */
1890 *lo = GC_get_stack_min(current_min);
1891 } else {
1892 /* Use the recent value to optimize search for min address. */
1893 *lo = GC_get_stack_min(*plast_stack_min);
1894 }
1895
1896 /* Remember current stack_min value. */
1897 if (thread != NULL) {
1898 UNPROTECT_THREAD(thread);
1899 }
1900 *plast_stack_min = *lo;
1901 }
1902
1903 #ifdef PARALLEL_MARK
1904
1905 # if defined(GC_PTHREADS) && !defined(GC_PTHREADS_PARAMARK)
1906 /* Use pthread-based parallel mark implementation. */
1907
1908 /* Workaround a deadlock in winpthreads-3.0b internals (observed */
1909 /* with MinGW 32/64). */
1910 # if !defined(__MINGW32__)
1911 # define GC_PTHREADS_PARAMARK
1912 # endif
1913 # endif
1914
1915 # if !defined(GC_PTHREADS_PARAMARK)
1916 STATIC HANDLE GC_marker_cv[MAX_MARKERS - 1] = {0};
1917 /* Events with manual reset (one for each */
1918 /* mark helper). */
1919
1920 STATIC DWORD GC_marker_Id[MAX_MARKERS - 1] = {0};
1921 /* This table is used for mapping helper */
1922 /* threads ID to mark helper index (linear */
1923 /* search is used since the mapping contains */
1924 /* only a few entries). */
1925 # endif
1926
1927 /* GC_mark_thread() is the same as in pthread_support.c */
1928 # ifdef GC_PTHREADS_PARAMARK
GC_mark_thread(void * id)1929 STATIC void * GC_mark_thread(void * id)
1930 # elif defined(MSWINCE)
1931 STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
1932 # else
1933 STATIC unsigned __stdcall GC_mark_thread(void * id)
1934 # endif
1935 {
1936 word my_mark_no = 0;
1937
1938 if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */
1939 marker_sp[(word)id] = GC_approx_sp();
1940 # ifdef IA64
1941 marker_bsp[(word)id] = GC_save_regs_in_stack();
1942 # endif
1943 # if !defined(GC_PTHREADS_PARAMARK)
1944 GC_marker_Id[(word)id] = GetCurrentThreadId();
1945 # endif
1946
1947 /* Inform GC_start_mark_threads about completion of marker data init. */
1948 GC_acquire_mark_lock();
1949 if (0 == --GC_fl_builder_count) /* count may have a negative value */
1950 GC_notify_all_builder();
1951
1952 for (;; ++my_mark_no) {
1953 if (my_mark_no - GC_mark_no > (word)2) {
1954 /* resynchronize if we get far off, e.g. because GC_mark_no */
1955 /* wrapped. */
1956 my_mark_no = GC_mark_no;
1957 }
1958 # ifdef DEBUG_THREADS
1959 GC_log_printf("Starting mark helper for mark number %lu\n",
1960 (unsigned long)my_mark_no);
1961 # endif
1962 GC_help_marker(my_mark_no);
1963 }
1964 }
1965
1966 # ifndef GC_ASSERTIONS
1967 # define SET_MARK_LOCK_HOLDER (void)0
1968 # define UNSET_MARK_LOCK_HOLDER (void)0
1969 # endif
1970
1971 /* GC_mark_threads[] is unused here unlike that in pthread_support.c */
1972
1973 # ifdef CAN_HANDLE_FORK
1974 static int available_markers_m1 = 0;
1975 # else
1976 # define available_markers_m1 GC_markers_m1
1977 # endif
1978
1979 # ifdef GC_PTHREADS_PARAMARK
1980 # include <pthread.h>
1981
1982 # if defined(GC_ASSERTIONS) && !defined(NUMERIC_THREAD_ID)
1983 # define NUMERIC_THREAD_ID(id) (unsigned long)(word)GC_PTHREAD_PTRVAL(id)
1984 /* Id not guaranteed to be unique. */
1985 # endif
1986
1987 # ifdef CAN_HANDLE_FORK
1988 static pthread_cond_t mark_cv;
1989 /* initialized by GC_start_mark_threads_inner */
1990 # else
1991 static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
1992 # endif
1993
1994 /* GC_start_mark_threads is the same as in pthread_support.c except */
1995 /* for thread stack that is assumed to be large enough. */
1996
GC_start_mark_threads_inner(void)1997 GC_INNER void GC_start_mark_threads_inner(void)
1998 {
1999 int i;
2000 pthread_attr_t attr;
2001 pthread_t new_thread;
2002 # ifndef NO_MARKER_SPECIAL_SIGMASK
2003 sigset_t set, oldset;
2004 # endif
2005
2006 GC_ASSERT(I_DONT_HOLD_LOCK());
2007 if (available_markers_m1 <= 0) return;
2008 /* Skip if parallel markers disabled or already started. */
2009 # ifdef CAN_HANDLE_FORK
2010 if (GC_parallel) return;
2011
2012 /* Reset mark_cv state after forking (as in pthread_support.c). */
2013 {
2014 pthread_cond_t mark_cv_local = PTHREAD_COND_INITIALIZER;
2015 BCOPY(&mark_cv_local, &mark_cv, sizeof(mark_cv));
2016 }
2017 # endif
2018
2019 GC_ASSERT(GC_fl_builder_count == 0);
2020 if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
2021 if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
2022 ABORT("pthread_attr_setdetachstate failed");
2023
2024 # ifndef NO_MARKER_SPECIAL_SIGMASK
2025 /* Apply special signal mask to GC marker threads, and don't drop */
2026 /* user defined signals by GC marker threads. */
2027 if (sigfillset(&set) != 0)
2028 ABORT("sigfillset failed");
2029 if (pthread_sigmask(SIG_BLOCK, &set, &oldset) < 0) {
2030 WARN("pthread_sigmask set failed, no markers started,"
2031 " errno = %" WARN_PRIdPTR "\n", errno);
2032 GC_markers_m1 = 0;
2033 (void)pthread_attr_destroy(&attr);
2034 return;
2035 }
2036 # endif /* !NO_MARKER_SPECIAL_SIGMASK */
2037
2038 # ifdef CAN_HANDLE_FORK
2039 /* To have proper GC_parallel value in GC_help_marker. */
2040 GC_markers_m1 = available_markers_m1;
2041 # endif
2042 for (i = 0; i < available_markers_m1; ++i) {
2043 marker_last_stack_min[i] = ADDR_LIMIT;
2044 if (0 != pthread_create(&new_thread, &attr,
2045 GC_mark_thread, (void *)(word)i)) {
2046 WARN("Marker thread creation failed\n", 0);
2047 /* Don't try to create other marker threads. */
2048 GC_markers_m1 = i;
2049 break;
2050 }
2051 }
2052
2053 # ifndef NO_MARKER_SPECIAL_SIGMASK
2054 /* Restore previous signal mask. */
2055 if (pthread_sigmask(SIG_SETMASK, &oldset, NULL) < 0) {
2056 WARN("pthread_sigmask restore failed, errno = %" WARN_PRIdPTR "\n",
2057 errno);
2058 }
2059 # endif
2060
2061 (void)pthread_attr_destroy(&attr);
2062 GC_wait_for_markers_init();
2063 GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
2064 }
2065
2066 # ifdef GC_ASSERTIONS
2067 STATIC unsigned long GC_mark_lock_holder = NO_THREAD;
2068 # define SET_MARK_LOCK_HOLDER \
2069 (void)(GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self()))
2070 # define UNSET_MARK_LOCK_HOLDER \
2071 do { \
2072 GC_ASSERT(GC_mark_lock_holder \
2073 == NUMERIC_THREAD_ID(pthread_self())); \
2074 GC_mark_lock_holder = NO_THREAD; \
2075 } while (0)
2076 # endif /* GC_ASSERTIONS */
2077
2078 static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
2079
2080 static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
2081
2082 /* GC_acquire/release_mark_lock(), GC_wait_builder/marker(), */
2083 /* GC_wait_for_reclaim(), GC_notify_all_builder/marker() are the same */
2084 /* as in pthread_support.c except that GC_generic_lock() is not used. */
2085
2086 # ifdef LOCK_STATS
2087 volatile AO_t GC_block_count = 0;
2088 # endif
2089
GC_acquire_mark_lock(void)2090 GC_INNER void GC_acquire_mark_lock(void)
2091 {
2092 # if defined(NUMERIC_THREAD_ID_UNIQUE) && !defined(THREAD_SANITIZER)
2093 GC_ASSERT(GC_mark_lock_holder != NUMERIC_THREAD_ID(pthread_self()));
2094 # endif
2095 if (pthread_mutex_lock(&mark_mutex) != 0) {
2096 ABORT("pthread_mutex_lock failed");
2097 }
2098 # ifdef LOCK_STATS
2099 (void)AO_fetch_and_add1(&GC_block_count);
2100 # endif
2101 /* GC_generic_lock(&mark_mutex); */
2102 SET_MARK_LOCK_HOLDER;
2103 }
2104
GC_release_mark_lock(void)2105 GC_INNER void GC_release_mark_lock(void)
2106 {
2107 UNSET_MARK_LOCK_HOLDER;
2108 if (pthread_mutex_unlock(&mark_mutex) != 0) {
2109 ABORT("pthread_mutex_unlock failed");
2110 }
2111 }
2112
2113 /* Collector must wait for a freelist builders for 2 reasons: */
2114 /* 1) Mark bits may still be getting examined without lock. */
2115 /* 2) Partial free lists referenced only by locals may not be */
2116 /* scanned correctly, e.g. if they contain "pointer-free" objects, */
2117 /* since the free-list link may be ignored. */
GC_wait_builder(void)2118 STATIC void GC_wait_builder(void)
2119 {
2120 UNSET_MARK_LOCK_HOLDER;
2121 if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
2122 ABORT("pthread_cond_wait failed");
2123 }
2124 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
2125 SET_MARK_LOCK_HOLDER;
2126 }
2127
GC_wait_for_reclaim(void)2128 GC_INNER void GC_wait_for_reclaim(void)
2129 {
2130 GC_acquire_mark_lock();
2131 while (GC_fl_builder_count > 0) {
2132 GC_wait_builder();
2133 }
2134 GC_release_mark_lock();
2135 }
2136
GC_notify_all_builder(void)2137 GC_INNER void GC_notify_all_builder(void)
2138 {
2139 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
2140 if (pthread_cond_broadcast(&builder_cv) != 0) {
2141 ABORT("pthread_cond_broadcast failed");
2142 }
2143 }
2144
GC_wait_marker(void)2145 GC_INNER void GC_wait_marker(void)
2146 {
2147 GC_ASSERT(GC_parallel);
2148 UNSET_MARK_LOCK_HOLDER;
2149 if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
2150 ABORT("pthread_cond_wait failed");
2151 }
2152 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
2153 SET_MARK_LOCK_HOLDER;
2154 }
2155
GC_notify_all_marker(void)2156 GC_INNER void GC_notify_all_marker(void)
2157 {
2158 GC_ASSERT(GC_parallel);
2159 if (pthread_cond_broadcast(&mark_cv) != 0) {
2160 ABORT("pthread_cond_broadcast failed");
2161 }
2162 }
2163
2164 # else /* ! GC_PTHREADS_PARAMARK */
2165
2166 # ifndef MARK_THREAD_STACK_SIZE
2167 # define MARK_THREAD_STACK_SIZE 0 /* default value */
2168 # endif
2169
2170 /* mark_mutex_event, builder_cv, mark_cv are initialized in GC_thr_init */
2171 static HANDLE mark_mutex_event = (HANDLE)0; /* Event with auto-reset. */
2172 static HANDLE builder_cv = (HANDLE)0; /* Event with manual reset. */
2173 static HANDLE mark_cv = (HANDLE)0; /* Event with manual reset. */
2174
GC_start_mark_threads_inner(void)2175 GC_INNER void GC_start_mark_threads_inner(void)
2176 {
2177 int i;
2178
2179 GC_ASSERT(I_DONT_HOLD_LOCK());
2180 if (available_markers_m1 <= 0) return;
2181
2182 GC_ASSERT(GC_fl_builder_count == 0);
2183 /* Initialize GC_marker_cv[] fully before starting the */
2184 /* first helper thread. */
2185 for (i = 0; i < GC_markers_m1; ++i) {
2186 if ((GC_marker_cv[i] = CreateEvent(NULL /* attrs */,
2187 TRUE /* isManualReset */,
2188 FALSE /* initialState */,
2189 NULL /* name (A/W) */)) == (HANDLE)0)
2190 ABORT("CreateEvent failed");
2191 }
2192
2193 for (i = 0; i < GC_markers_m1; ++i) {
2194 # if defined(MSWINCE) || defined(MSWIN_XBOX1)
2195 HANDLE handle;
2196 DWORD thread_id;
2197
2198 marker_last_stack_min[i] = ADDR_LIMIT;
2199 /* There is no _beginthreadex() in WinCE. */
2200 handle = CreateThread(NULL /* lpsa */,
2201 MARK_THREAD_STACK_SIZE /* ignored */,
2202 GC_mark_thread, (LPVOID)(word)i,
2203 0 /* fdwCreate */, &thread_id);
2204 if (handle == NULL) {
2205 WARN("Marker thread creation failed\n", 0);
2206 /* The most probable failure reason is "not enough memory". */
2207 /* Don't try to create other marker threads. */
2208 break;
2209 } else {
2210 /* It's safe to detach the thread. */
2211 CloseHandle(handle);
2212 }
2213 # else
2214 GC_uintptr_t handle;
2215 unsigned thread_id;
2216
2217 marker_last_stack_min[i] = ADDR_LIMIT;
2218 handle = _beginthreadex(NULL /* security_attr */,
2219 MARK_THREAD_STACK_SIZE, GC_mark_thread,
2220 (void *)(word)i, 0 /* flags */, &thread_id);
2221 if (!handle || handle == (GC_uintptr_t)-1L) {
2222 WARN("Marker thread creation failed\n", 0);
2223 /* Don't try to create other marker threads. */
2224 break;
2225 } else {/* We may detach the thread (if handle is of HANDLE type) */
2226 /* CloseHandle((HANDLE)handle); */
2227 }
2228 # endif
2229 }
2230
2231 /* Adjust GC_markers_m1 (and free unused resources) if failed. */
2232 while (GC_markers_m1 > i) {
2233 GC_markers_m1--;
2234 CloseHandle(GC_marker_cv[GC_markers_m1]);
2235 }
2236 GC_wait_for_markers_init();
2237 GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
2238 if (i == 0) {
2239 CloseHandle(mark_cv);
2240 CloseHandle(builder_cv);
2241 CloseHandle(mark_mutex_event);
2242 }
2243 }
2244
2245 # ifdef GC_ASSERTIONS
2246 STATIC DWORD GC_mark_lock_holder = NO_THREAD;
2247 # define SET_MARK_LOCK_HOLDER \
2248 (void)(GC_mark_lock_holder = GetCurrentThreadId())
2249 # define UNSET_MARK_LOCK_HOLDER \
2250 do { \
2251 GC_ASSERT(GC_mark_lock_holder == GetCurrentThreadId()); \
2252 GC_mark_lock_holder = NO_THREAD; \
2253 } while (0)
2254 # endif /* GC_ASSERTIONS */
2255
2256 STATIC /* volatile */ LONG GC_mark_mutex_state = 0;
2257 /* Mutex state: 0 - unlocked, */
2258 /* 1 - locked and no other waiters, */
2259 /* -1 - locked and waiters may exist. */
2260 /* Accessed by InterlockedExchange(). */
2261
2262 /* #define LOCK_STATS */
2263 # ifdef LOCK_STATS
2264 volatile AO_t GC_block_count = 0;
2265 volatile AO_t GC_unlocked_count = 0;
2266 # endif
2267
GC_acquire_mark_lock(void)2268 GC_INNER void GC_acquire_mark_lock(void)
2269 {
2270 # ifndef THREAD_SANITIZER
2271 GC_ASSERT(GC_mark_lock_holder != GetCurrentThreadId());
2272 # endif
2273 if (InterlockedExchange(&GC_mark_mutex_state, 1 /* locked */) != 0) {
2274 # ifdef LOCK_STATS
2275 (void)AO_fetch_and_add1(&GC_block_count);
2276 # endif
2277 /* Repeatedly reset the state and wait until acquire the lock. */
2278 while (InterlockedExchange(&GC_mark_mutex_state,
2279 -1 /* locked_and_has_waiters */) != 0) {
2280 if (WaitForSingleObject(mark_mutex_event, INFINITE) == WAIT_FAILED)
2281 ABORT("WaitForSingleObject failed");
2282 }
2283 }
2284 # ifdef LOCK_STATS
2285 else {
2286 (void)AO_fetch_and_add1(&GC_unlocked_count);
2287 }
2288 # endif
2289
2290 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
2291 SET_MARK_LOCK_HOLDER;
2292 }
2293
GC_release_mark_lock(void)2294 GC_INNER void GC_release_mark_lock(void)
2295 {
2296 UNSET_MARK_LOCK_HOLDER;
2297 if (InterlockedExchange(&GC_mark_mutex_state, 0 /* unlocked */) < 0) {
2298 /* wake a waiter */
2299 if (SetEvent(mark_mutex_event) == FALSE)
2300 ABORT("SetEvent failed");
2301 }
2302 }
2303
2304 /* In GC_wait_for_reclaim/GC_notify_all_builder() we emulate POSIX */
2305 /* cond_wait/cond_broadcast() primitives with WinAPI Event object */
2306 /* (working in "manual reset" mode). This works here because */
2307 /* GC_notify_all_builder() is always called holding lock on */
2308 /* mark_mutex and the checked condition (GC_fl_builder_count == 0) */
2309 /* is the only one for which broadcasting on builder_cv is performed. */
2310
GC_wait_for_reclaim(void)2311 GC_INNER void GC_wait_for_reclaim(void)
2312 {
2313 GC_ASSERT(builder_cv != 0);
2314 for (;;) {
2315 GC_acquire_mark_lock();
2316 if (GC_fl_builder_count == 0)
2317 break;
2318 if (ResetEvent(builder_cv) == FALSE)
2319 ABORT("ResetEvent failed");
2320 GC_release_mark_lock();
2321 if (WaitForSingleObject(builder_cv, INFINITE) == WAIT_FAILED)
2322 ABORT("WaitForSingleObject failed");
2323 }
2324 GC_release_mark_lock();
2325 }
2326
GC_notify_all_builder(void)2327 GC_INNER void GC_notify_all_builder(void)
2328 {
2329 GC_ASSERT(GC_mark_lock_holder == GetCurrentThreadId());
2330 GC_ASSERT(builder_cv != 0);
2331 GC_ASSERT(GC_fl_builder_count == 0);
2332 if (SetEvent(builder_cv) == FALSE)
2333 ABORT("SetEvent failed");
2334 }
2335
2336 /* mark_cv is used (for waiting) by a non-helper thread. */
2337
GC_wait_marker(void)2338 GC_INNER void GC_wait_marker(void)
2339 {
2340 HANDLE event = mark_cv;
2341 DWORD thread_id = GetCurrentThreadId();
2342 int i = GC_markers_m1;
2343
2344 while (i-- > 0) {
2345 if (GC_marker_Id[i] == thread_id) {
2346 event = GC_marker_cv[i];
2347 break;
2348 }
2349 }
2350
2351 if (ResetEvent(event) == FALSE)
2352 ABORT("ResetEvent failed");
2353 GC_release_mark_lock();
2354 if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED)
2355 ABORT("WaitForSingleObject failed");
2356 GC_acquire_mark_lock();
2357 }
2358
GC_notify_all_marker(void)2359 GC_INNER void GC_notify_all_marker(void)
2360 {
2361 DWORD thread_id = GetCurrentThreadId();
2362 int i = GC_markers_m1;
2363
2364 while (i-- > 0) {
2365 /* Notify every marker ignoring self (for efficiency). */
2366 if (SetEvent(GC_marker_Id[i] != thread_id ? GC_marker_cv[i] :
2367 mark_cv) == FALSE)
2368 ABORT("SetEvent failed");
2369 }
2370 }
2371
2372 # endif /* ! GC_PTHREADS_PARAMARK */
2373
2374 #endif /* PARALLEL_MARK */
2375
2376 /* We have no DllMain to take care of new threads. Thus we */
2377 /* must properly intercept thread creation. */
2378
2379 typedef struct {
2380 LPTHREAD_START_ROUTINE start;
2381 LPVOID param;
2382 } thread_args;
2383
GC_win32_start_inner(struct GC_stack_base * sb,void * arg)2384 STATIC void * GC_CALLBACK GC_win32_start_inner(struct GC_stack_base *sb,
2385 void *arg)
2386 {
2387 void * ret;
2388 LPTHREAD_START_ROUTINE start = ((thread_args *)arg)->start;
2389 LPVOID param = ((thread_args *)arg)->param;
2390
2391 GC_register_my_thread(sb); /* This waits for an in-progress GC. */
2392
2393 # ifdef DEBUG_THREADS
2394 GC_log_printf("thread 0x%lx starting...\n", (long)GetCurrentThreadId());
2395 # endif
2396
2397 GC_free(arg);
2398
2399 /* Clear the thread entry even if we exit with an exception. */
2400 /* This is probably pointless, since an uncaught exception is */
2401 /* supposed to result in the process being killed. */
2402 # ifndef __GNUC__
2403 ret = NULL; /* to suppress "might be uninitialized" compiler warning */
2404 __try
2405 # endif
2406 {
2407 ret = (void *)(word)(*start)(param);
2408 }
2409 # ifndef __GNUC__
2410 __finally
2411 # endif
2412 {
2413 GC_unregister_my_thread();
2414 }
2415
2416 # ifdef DEBUG_THREADS
2417 GC_log_printf("thread 0x%lx returned from start routine\n",
2418 (long)GetCurrentThreadId());
2419 # endif
2420 return ret;
2421 }
2422
GC_win32_start(LPVOID arg)2423 STATIC DWORD WINAPI GC_win32_start(LPVOID arg)
2424 {
2425 return (DWORD)(word)GC_call_with_stack_base(GC_win32_start_inner, arg);
2426 }
2427
GC_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,GC_WIN32_SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId)2428 GC_API HANDLE WINAPI GC_CreateThread(
2429 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2430 GC_WIN32_SIZE_T dwStackSize,
2431 LPTHREAD_START_ROUTINE lpStartAddress,
2432 LPVOID lpParameter, DWORD dwCreationFlags,
2433 LPDWORD lpThreadId)
2434 {
2435 if (!EXPECT(parallel_initialized, TRUE))
2436 GC_init_parallel();
2437 /* make sure GC is initialized (i.e. main thread is */
2438 /* attached, tls initialized). */
2439
2440 # ifdef DEBUG_THREADS
2441 GC_log_printf("About to create a thread from 0x%lx\n",
2442 (long)GetCurrentThreadId());
2443 # endif
2444 if (GC_win32_dll_threads) {
2445 return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
2446 lpParameter, dwCreationFlags, lpThreadId);
2447 } else {
2448 thread_args *args =
2449 (thread_args *)GC_malloc_uncollectable(sizeof(thread_args));
2450 /* Handed off to and deallocated by child thread. */
2451 HANDLE thread_h;
2452
2453 if (NULL == args) {
2454 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2455 return NULL;
2456 }
2457
2458 /* set up thread arguments */
2459 args -> start = lpStartAddress;
2460 args -> param = lpParameter;
2461 GC_dirty(args);
2462 REACHABLE_AFTER_DIRTY(lpParameter);
2463
2464 set_need_to_lock();
2465 thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
2466 args, dwCreationFlags, lpThreadId);
2467 if (thread_h == 0) GC_free(args);
2468 return thread_h;
2469 }
2470 }
2471
GC_ExitThread(DWORD dwExitCode)2472 GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(DWORD dwExitCode)
2473 {
2474 GC_unregister_my_thread();
2475 ExitThread(dwExitCode);
2476 }
2477
2478 # if !defined(CYGWIN32) && !defined(MSWINCE) && !defined(MSWIN_XBOX1)
GC_beginthreadex(void * security,unsigned stack_size,unsigned (__stdcall * start_address)(void *),void * arglist,unsigned initflag,unsigned * thrdaddr)2479 GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
2480 void *security, unsigned stack_size,
2481 unsigned (__stdcall *start_address)(void *),
2482 void *arglist, unsigned initflag,
2483 unsigned *thrdaddr)
2484 {
2485 if (!EXPECT(parallel_initialized, TRUE))
2486 GC_init_parallel();
2487 /* make sure GC is initialized (i.e. main thread is */
2488 /* attached, tls initialized). */
2489 # ifdef DEBUG_THREADS
2490 GC_log_printf("About to create a thread from 0x%lx\n",
2491 (long)GetCurrentThreadId());
2492 # endif
2493
2494 if (GC_win32_dll_threads) {
2495 return _beginthreadex(security, stack_size, start_address,
2496 arglist, initflag, thrdaddr);
2497 } else {
2498 GC_uintptr_t thread_h;
2499 thread_args *args =
2500 (thread_args *)GC_malloc_uncollectable(sizeof(thread_args));
2501 /* Handed off to and deallocated by child thread. */
2502
2503 if (NULL == args) {
2504 /* MSDN docs say _beginthreadex() returns 0 on error and sets */
2505 /* errno to either EAGAIN (too many threads) or EINVAL (the */
2506 /* argument is invalid or the stack size is incorrect), so we */
2507 /* set errno to EAGAIN on "not enough memory". */
2508 errno = EAGAIN;
2509 return 0;
2510 }
2511
2512 /* set up thread arguments */
2513 args -> start = (LPTHREAD_START_ROUTINE)start_address;
2514 args -> param = arglist;
2515 GC_dirty(args);
2516 REACHABLE_AFTER_DIRTY(arglist);
2517
2518 set_need_to_lock();
2519 thread_h = _beginthreadex(security, stack_size,
2520 (unsigned (__stdcall *)(void *))GC_win32_start,
2521 args, initflag, thrdaddr);
2522 if (thread_h == 0) GC_free(args);
2523 return thread_h;
2524 }
2525 }
2526
GC_endthreadex(unsigned retval)2527 GC_API void GC_CALL GC_endthreadex(unsigned retval)
2528 {
2529 GC_unregister_my_thread();
2530 _endthreadex(retval);
2531 }
2532 # endif /* !CYGWIN32 && !MSWINCE && !MSWIN_XBOX1 */
2533
2534 #ifdef GC_WINMAIN_REDIRECT
2535 /* This might be useful on WinCE. Shouldn't be used with GC_DLL. */
2536
2537 # if defined(MSWINCE) && defined(UNDER_CE)
2538 # define WINMAIN_LPTSTR LPWSTR
2539 # else
2540 # define WINMAIN_LPTSTR LPSTR
2541 # endif
2542
2543 /* This is defined in gc.h. */
2544 # undef WinMain
2545
2546 /* Defined outside GC by an application. */
2547 int WINAPI GC_WinMain(HINSTANCE, HINSTANCE, WINMAIN_LPTSTR, int);
2548
2549 typedef struct {
2550 HINSTANCE hInstance;
2551 HINSTANCE hPrevInstance;
2552 WINMAIN_LPTSTR lpCmdLine;
2553 int nShowCmd;
2554 } main_thread_args;
2555
main_thread_start(LPVOID arg)2556 static DWORD WINAPI main_thread_start(LPVOID arg)
2557 {
2558 main_thread_args * args = (main_thread_args *) arg;
2559 return (DWORD)GC_WinMain(args->hInstance, args->hPrevInstance,
2560 args->lpCmdLine, args->nShowCmd);
2561 }
2562
GC_waitForSingleObjectInfinite(void * handle)2563 STATIC void * GC_waitForSingleObjectInfinite(void * handle)
2564 {
2565 return (void *)(word)WaitForSingleObject((HANDLE)handle, INFINITE);
2566 }
2567
2568 # ifndef WINMAIN_THREAD_STACK_SIZE
2569 # define WINMAIN_THREAD_STACK_SIZE 0 /* default value */
2570 # endif
2571
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,WINMAIN_LPTSTR lpCmdLine,int nShowCmd)2572 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2573 WINMAIN_LPTSTR lpCmdLine, int nShowCmd)
2574 {
2575 DWORD exit_code = 1;
2576
2577 main_thread_args args = {
2578 hInstance, hPrevInstance, lpCmdLine, nShowCmd
2579 };
2580 HANDLE thread_h;
2581 DWORD thread_id;
2582
2583 /* initialize everything */
2584 GC_INIT();
2585
2586 /* start the main thread */
2587 thread_h = GC_CreateThread(NULL /* lpsa */,
2588 WINMAIN_THREAD_STACK_SIZE /* ignored on WinCE */,
2589 main_thread_start, &args, 0 /* fdwCreate */,
2590 &thread_id);
2591
2592 if (thread_h != NULL) {
2593 if ((DWORD)(word)GC_do_blocking(GC_waitForSingleObjectInfinite,
2594 (void *)thread_h) == WAIT_FAILED)
2595 ABORT("WaitForSingleObject(main_thread) failed");
2596 GetExitCodeThread (thread_h, &exit_code);
2597 CloseHandle (thread_h);
2598 } else {
2599 ABORT("GC_CreateThread(main_thread) failed");
2600 }
2601
2602 # ifdef MSWINCE
2603 GC_deinit();
2604 # endif
2605 return (int) exit_code;
2606 }
2607
2608 #endif /* GC_WINMAIN_REDIRECT */
2609
GC_thr_init(void)2610 GC_INNER void GC_thr_init(void)
2611 {
2612 struct GC_stack_base sb;
2613
2614 GC_ASSERT(I_HOLD_LOCK());
2615 if (GC_thr_initialized) return;
2616
2617 GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
2618 GC_main_thread = GetCurrentThreadId();
2619 GC_thr_initialized = TRUE;
2620
2621 # ifdef CAN_HANDLE_FORK
2622 /* Prepare for forks if requested. */
2623 if (GC_handle_fork) {
2624 # ifdef CAN_CALL_ATFORK
2625 if (pthread_atfork(fork_prepare_proc, fork_parent_proc,
2626 fork_child_proc) == 0) {
2627 /* Handlers successfully registered. */
2628 GC_handle_fork = 1;
2629 } else
2630 # endif
2631 /* else */ if (GC_handle_fork != -1)
2632 ABORT("pthread_atfork failed");
2633 }
2634 # endif
2635
2636 # ifdef WOW64_THREAD_CONTEXT_WORKAROUND
2637 /* Set isWow64 flag. */
2638 {
2639 HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
2640 if (hK32) {
2641 FARPROC pfn = GetProcAddress(hK32, "IsWow64Process");
2642 if (pfn
2643 && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))(word)pfn)(
2644 GetCurrentProcess(), &isWow64))
2645 isWow64 = FALSE; /* IsWow64Process failed */
2646 }
2647 }
2648 # endif
2649
2650 /* Add the initial thread, so we can stop it. */
2651 sb.mem_base = GC_stackbottom;
2652 GC_ASSERT(sb.mem_base != NULL);
2653 # ifdef IA64
2654 sb.reg_base = GC_register_stackbottom;
2655 # endif
2656
2657 # if defined(PARALLEL_MARK)
2658 {
2659 char * markers_string = GETENV("GC_MARKERS");
2660 int markers;
2661
2662 if (markers_string != NULL) {
2663 markers = atoi(markers_string);
2664 if (markers <= 0 || markers > MAX_MARKERS) {
2665 WARN("Too big or invalid number of mark threads: %" WARN_PRIdPTR
2666 "; using maximum threads\n", (signed_word)markers);
2667 markers = MAX_MARKERS;
2668 }
2669 } else {
2670 # ifdef MSWINCE
2671 /* There is no GetProcessAffinityMask() in WinCE. */
2672 /* GC_sysinfo is already initialized. */
2673 markers = (int)GC_sysinfo.dwNumberOfProcessors;
2674 # else
2675 # ifdef _WIN64
2676 DWORD_PTR procMask = 0;
2677 DWORD_PTR sysMask;
2678 # else
2679 DWORD procMask = 0;
2680 DWORD sysMask;
2681 # endif
2682 int ncpu = 0;
2683 if (
2684 # ifdef __cplusplus
2685 GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask)
2686 # else
2687 /* Cast args to void* for compatibility with some old SDKs. */
2688 GetProcessAffinityMask(GetCurrentProcess(),
2689 (void *)&procMask, (void *)&sysMask)
2690 # endif
2691 && procMask) {
2692 do {
2693 ncpu++;
2694 } while ((procMask &= procMask - 1) != 0);
2695 }
2696 markers = ncpu;
2697 # endif
2698 # if defined(GC_MIN_MARKERS) && !defined(CPPCHECK)
2699 /* This is primarily for testing on systems without getenv(). */
2700 if (markers < GC_MIN_MARKERS)
2701 markers = GC_MIN_MARKERS;
2702 # endif
2703 if (markers > MAX_MARKERS)
2704 markers = MAX_MARKERS; /* silently limit the value */
2705 }
2706 available_markers_m1 = markers - 1;
2707 }
2708
2709 /* Check whether parallel mode could be enabled. */
2710 {
2711 if (GC_win32_dll_threads || available_markers_m1 <= 0) {
2712 /* Disable parallel marking. */
2713 GC_parallel = FALSE;
2714 GC_COND_LOG_PRINTF(
2715 "Single marker thread, turning off parallel marking\n");
2716 } else {
2717 # ifndef GC_PTHREADS_PARAMARK
2718 /* Initialize Win32 event objects for parallel marking. */
2719 mark_mutex_event = CreateEvent(NULL /* attrs */,
2720 FALSE /* isManualReset */,
2721 FALSE /* initialState */, NULL /* name */);
2722 builder_cv = CreateEvent(NULL /* attrs */,
2723 TRUE /* isManualReset */,
2724 FALSE /* initialState */, NULL /* name */);
2725 mark_cv = CreateEvent(NULL /* attrs */, TRUE /* isManualReset */,
2726 FALSE /* initialState */, NULL /* name */);
2727 if (mark_mutex_event == (HANDLE)0 || builder_cv == (HANDLE)0
2728 || mark_cv == (HANDLE)0)
2729 ABORT("CreateEvent failed");
2730 # endif
2731 /* Disable true incremental collection, but generational is OK. */
2732 GC_time_limit = GC_TIME_UNLIMITED;
2733 }
2734 }
2735 # endif /* PARALLEL_MARK */
2736
2737 GC_ASSERT(0 == GC_lookup_thread_inner(GC_main_thread));
2738 GC_register_my_thread_inner(&sb, GC_main_thread);
2739 }
2740
2741 #ifdef GC_PTHREADS
2742
2743 struct start_info {
2744 void *(*start_routine)(void *);
2745 void *arg;
2746 GC_bool detached;
2747 };
2748
GC_pthread_join(pthread_t pthread_id,void ** retval)2749 GC_API int GC_pthread_join(pthread_t pthread_id, void **retval)
2750 {
2751 int result;
2752 # ifndef GC_WIN32_PTHREADS
2753 GC_thread t;
2754 # endif
2755 DCL_LOCK_STATE;
2756
2757 GC_ASSERT(!GC_win32_dll_threads);
2758 # ifdef DEBUG_THREADS
2759 GC_log_printf("thread %p(0x%lx) is joining thread %p\n",
2760 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2761 (long)GetCurrentThreadId(),
2762 (void *)GC_PTHREAD_PTRVAL(pthread_id));
2763 # endif
2764
2765 /* Thread being joined might not have registered itself yet. */
2766 /* After the join, thread id may have been recycled. */
2767 /* FIXME: It would be better if this worked more like */
2768 /* pthread_support.c. */
2769 # ifndef GC_WIN32_PTHREADS
2770 while ((t = GC_lookup_pthread(pthread_id)) == 0)
2771 Sleep(10);
2772 # endif
2773 result = pthread_join(pthread_id, retval);
2774 if (0 == result) {
2775 # ifdef GC_WIN32_PTHREADS
2776 /* pthreads-win32 and winpthreads id are unique (not recycled). */
2777 GC_thread t = GC_lookup_pthread(pthread_id);
2778 if (NULL == t) ABORT("Thread not registered");
2779 # endif
2780
2781 LOCK();
2782 if ((t -> flags & FINISHED) != 0) {
2783 GC_delete_gc_thread_no_free(t);
2784 GC_INTERNAL_FREE(t);
2785 }
2786 UNLOCK();
2787 }
2788
2789 # ifdef DEBUG_THREADS
2790 GC_log_printf("thread %p(0x%lx) join with thread %p %s\n",
2791 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2792 (long)GetCurrentThreadId(),
2793 (void *)GC_PTHREAD_PTRVAL(pthread_id),
2794 result != 0 ? "failed" : "succeeded");
2795 # endif
2796 return result;
2797 }
2798
2799 /* Cygwin-pthreads calls CreateThread internally, but it's not easily */
2800 /* interceptable by us..., so intercept pthread_create instead. */
GC_pthread_create(pthread_t * new_thread,GC_PTHREAD_CREATE_CONST pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)2801 GC_API int GC_pthread_create(pthread_t *new_thread,
2802 GC_PTHREAD_CREATE_CONST pthread_attr_t *attr,
2803 void *(*start_routine)(void *), void *arg)
2804 {
2805 int result;
2806 struct start_info * si;
2807
2808 if (!EXPECT(parallel_initialized, TRUE))
2809 GC_init_parallel();
2810 /* make sure GC is initialized (i.e. main thread is attached) */
2811 GC_ASSERT(!GC_win32_dll_threads);
2812
2813 /* This is otherwise saved only in an area mmapped by the thread */
2814 /* library, which isn't visible to the collector. */
2815 si = (struct start_info *)GC_malloc_uncollectable(
2816 sizeof(struct start_info));
2817 if (NULL == si)
2818 return EAGAIN;
2819
2820 si -> start_routine = start_routine;
2821 si -> arg = arg;
2822 GC_dirty(si);
2823 REACHABLE_AFTER_DIRTY(arg);
2824 if (attr != 0 &&
2825 pthread_attr_getdetachstate(attr, &si->detached)
2826 == PTHREAD_CREATE_DETACHED) {
2827 si->detached = TRUE;
2828 }
2829
2830 # ifdef DEBUG_THREADS
2831 GC_log_printf("About to create a thread from %p(0x%lx)\n",
2832 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2833 (long)GetCurrentThreadId());
2834 # endif
2835 set_need_to_lock();
2836 result = pthread_create(new_thread, attr, GC_pthread_start, si);
2837
2838 if (result) { /* failure */
2839 GC_free(si);
2840 }
2841 return(result);
2842 }
2843
GC_pthread_start_inner(struct GC_stack_base * sb,void * arg)2844 STATIC void * GC_CALLBACK GC_pthread_start_inner(struct GC_stack_base *sb,
2845 void * arg)
2846 {
2847 struct start_info * si = (struct start_info *)arg;
2848 void * result;
2849 void *(*start)(void *);
2850 void *start_arg;
2851 DWORD thread_id = GetCurrentThreadId();
2852 pthread_t pthread_id = pthread_self();
2853 GC_thread me;
2854 DCL_LOCK_STATE;
2855
2856 # ifdef DEBUG_THREADS
2857 GC_log_printf("thread %p(0x%x) starting...\n",
2858 (void *)GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
2859 # endif
2860
2861 GC_ASSERT(!GC_win32_dll_threads);
2862 /* If a GC occurs before the thread is registered, that GC will */
2863 /* ignore this thread. That's fine, since it will block trying to */
2864 /* acquire the allocation lock, and won't yet hold interesting */
2865 /* pointers. */
2866 LOCK();
2867 /* We register the thread here instead of in the parent, so that */
2868 /* we don't need to hold the allocation lock during pthread_create. */
2869 me = GC_register_my_thread_inner(sb, thread_id);
2870 SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
2871 GC_ASSERT(me != &first_thread);
2872 me -> pthread_id = pthread_id;
2873 if (si->detached) me -> flags |= DETACHED;
2874 UNLOCK();
2875
2876 start = si -> start_routine;
2877 start_arg = si -> arg;
2878
2879 GC_free(si); /* was allocated uncollectible */
2880
2881 pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
2882 result = (*start)(start_arg);
2883 me -> status = result;
2884 GC_dirty(me);
2885 pthread_cleanup_pop(1);
2886
2887 # ifdef DEBUG_THREADS
2888 GC_log_printf("thread %p(0x%x) returned from start routine\n",
2889 (void *)GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
2890 # endif
2891 return(result);
2892 }
2893
GC_pthread_start(void * arg)2894 STATIC void * GC_pthread_start(void * arg)
2895 {
2896 return GC_call_with_stack_base(GC_pthread_start_inner, arg);
2897 }
2898
GC_thread_exit_proc(void * arg)2899 STATIC void GC_thread_exit_proc(void *arg)
2900 {
2901 GC_thread me = (GC_thread)arg;
2902 DCL_LOCK_STATE;
2903
2904 GC_ASSERT(!GC_win32_dll_threads);
2905 # ifdef DEBUG_THREADS
2906 GC_log_printf("thread %p(0x%lx) called pthread_exit()\n",
2907 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2908 (long)GetCurrentThreadId());
2909 # endif
2910
2911 LOCK();
2912 GC_wait_for_gc_completion(FALSE);
2913 # if defined(THREAD_LOCAL_ALLOC)
2914 GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
2915 GC_destroy_thread_local(&(me->tlfs));
2916 # endif
2917 if (me -> flags & DETACHED) {
2918 GC_delete_thread(GetCurrentThreadId());
2919 } else {
2920 /* deallocate it as part of join */
2921 me -> flags |= FINISHED;
2922 }
2923 # if defined(THREAD_LOCAL_ALLOC)
2924 /* It is required to call remove_specific defined in specific.c. */
2925 GC_remove_specific(GC_thread_key);
2926 # endif
2927 UNLOCK();
2928 }
2929
2930 # ifndef GC_NO_PTHREAD_SIGMASK
2931 /* Win32 pthread does not support sigmask. */
2932 /* So, nothing required here... */
GC_pthread_sigmask(int how,const sigset_t * set,sigset_t * oset)2933 GC_API int GC_pthread_sigmask(int how, const sigset_t *set,
2934 sigset_t *oset)
2935 {
2936 return pthread_sigmask(how, set, oset);
2937 }
2938 # endif /* !GC_NO_PTHREAD_SIGMASK */
2939
GC_pthread_detach(pthread_t thread)2940 GC_API int GC_pthread_detach(pthread_t thread)
2941 {
2942 int result;
2943 GC_thread t;
2944 DCL_LOCK_STATE;
2945
2946 GC_ASSERT(!GC_win32_dll_threads);
2947 /* The thread might not have registered itself yet. */
2948 /* TODO: Wait for registration of the created thread in pthread_create. */
2949 while ((t = GC_lookup_pthread(thread)) == NULL)
2950 Sleep(10);
2951 result = pthread_detach(thread);
2952 if (result == 0) {
2953 LOCK();
2954 t -> flags |= DETACHED;
2955 /* Here the pthread thread id may have been recycled. */
2956 if ((t -> flags & FINISHED) != 0) {
2957 GC_delete_gc_thread_no_free(t);
2958 GC_INTERNAL_FREE(t);
2959 }
2960 UNLOCK();
2961 }
2962 return result;
2963 }
2964
2965 #elif !defined(GC_NO_THREADS_DISCOVERY)
2966 /* We avoid acquiring locks here, since this doesn't seem to be */
2967 /* preemptible. This may run with an uninitialized collector, in */
2968 /* which case we don't do much. This implies that no threads other */
2969 /* than the main one should be created with an uninitialized */
2970 /* collector. (The alternative of initializing the collector here */
2971 /* seems dangerous, since DllMain is limited in what it can do.) */
2972
2973 # ifdef GC_INSIDE_DLL
2974 /* Export only if needed by client. */
2975 GC_API
2976 # else
2977 # define GC_DllMain DllMain
2978 # endif
GC_DllMain(HINSTANCE inst GC_ATTR_UNUSED,ULONG reason,LPVOID reserved GC_ATTR_UNUSED)2979 BOOL WINAPI GC_DllMain(HINSTANCE inst GC_ATTR_UNUSED, ULONG reason,
2980 LPVOID reserved GC_ATTR_UNUSED)
2981 {
2982 DWORD thread_id;
2983
2984 /* Note that GC_use_threads_discovery should be called by the */
2985 /* client application at start-up to activate automatic thread */
2986 /* registration (it is the default GC behavior since v7.0alpha7); */
2987 /* to always have automatic thread registration turned on, the GC */
2988 /* should be compiled with -D GC_DISCOVER_TASK_THREADS. */
2989 if (!GC_win32_dll_threads && parallel_initialized) return TRUE;
2990
2991 switch (reason) {
2992 case DLL_THREAD_ATTACH:
2993 # ifdef PARALLEL_MARK
2994 /* Don't register marker threads. */
2995 if (GC_parallel) {
2996 /* We could reach here only if parallel_initialized == FALSE. */
2997 break;
2998 }
2999 # endif
3000 /* FALLTHRU */
3001 case DLL_PROCESS_ATTACH:
3002 /* This may run with the collector uninitialized. */
3003 thread_id = GetCurrentThreadId();
3004 if (parallel_initialized && GC_main_thread != thread_id) {
3005 # ifdef PARALLEL_MARK
3006 ABORT("Cannot initialize parallel marker from DllMain");
3007 # else
3008 struct GC_stack_base sb;
3009 /* Don't lock here. */
3010 # ifdef GC_ASSERTIONS
3011 int sb_result =
3012 # endif
3013 GC_get_stack_base(&sb);
3014 GC_ASSERT(sb_result == GC_SUCCESS);
3015 GC_register_my_thread_inner(&sb, thread_id);
3016 # endif
3017 } /* o.w. we already did it during GC_thr_init, called by GC_init */
3018 break;
3019
3020 case DLL_THREAD_DETACH:
3021 /* We are hopefully running in the context of the exiting thread. */
3022 GC_ASSERT(parallel_initialized);
3023 if (GC_win32_dll_threads) {
3024 GC_delete_thread(GetCurrentThreadId());
3025 }
3026 break;
3027
3028 case DLL_PROCESS_DETACH:
3029 if (GC_win32_dll_threads) {
3030 int i;
3031 int my_max = (int)GC_get_max_thread_index();
3032
3033 for (i = 0; i <= my_max; ++i) {
3034 if (AO_load(&(dll_thread_table[i].tm.in_use)))
3035 GC_delete_gc_thread_no_free(&dll_thread_table[i]);
3036 }
3037 GC_deinit();
3038 }
3039 break;
3040 }
3041 return TRUE;
3042 }
3043 #endif /* !GC_NO_THREADS_DISCOVERY && !GC_PTHREADS */
3044
3045 /* Perform all initializations, including those that */
3046 /* may require allocation. */
3047 /* Called without allocation lock. */
3048 /* Must be called before a second thread is created. */
GC_init_parallel(void)3049 GC_INNER void GC_init_parallel(void)
3050 {
3051 # if defined(THREAD_LOCAL_ALLOC)
3052 GC_thread me;
3053 DCL_LOCK_STATE;
3054 # endif
3055
3056 if (parallel_initialized) return;
3057 parallel_initialized = TRUE;
3058 /* GC_init() calls us back, so set flag first. */
3059
3060 if (!GC_is_initialized) GC_init();
3061 # if defined(CPPCHECK) && !defined(GC_NO_THREADS_DISCOVERY)
3062 GC_noop1((word)&GC_DllMain);
3063 # endif
3064 if (GC_win32_dll_threads) {
3065 set_need_to_lock();
3066 /* Cannot intercept thread creation. Hence we don't know if */
3067 /* other threads exist. However, client is not allowed to */
3068 /* create other threads before collector initialization. */
3069 /* Thus it's OK not to lock before this. */
3070 }
3071 /* Initialize thread local free lists if used. */
3072 # if defined(THREAD_LOCAL_ALLOC)
3073 LOCK();
3074 me = GC_lookup_thread_inner(GetCurrentThreadId());
3075 CHECK_LOOKUP_MY_THREAD(me);
3076 GC_init_thread_local(&me->tlfs);
3077 UNLOCK();
3078 # endif
3079 }
3080
3081 #if defined(USE_PTHREAD_LOCKS)
3082 /* Support for pthread locking code. */
3083 /* pthread_mutex_trylock may not win here, */
3084 /* due to builtin support for spinning first? */
3085
GC_lock(void)3086 GC_INNER void GC_lock(void)
3087 {
3088 pthread_mutex_lock(&GC_allocate_ml);
3089 }
3090 #endif /* USE_PTHREAD_LOCKS */
3091
3092 #if defined(THREAD_LOCAL_ALLOC)
3093
3094 /* Add thread-local allocation support. VC++ uses __declspec(thread). */
3095
3096 /* We must explicitly mark ptrfree and gcj free lists, since the free */
3097 /* list links wouldn't otherwise be found. We also set them in the */
3098 /* normal free lists, since that involves touching less memory than if */
3099 /* we scanned them normally. */
GC_mark_thread_local_free_lists(void)3100 GC_INNER void GC_mark_thread_local_free_lists(void)
3101 {
3102 int i;
3103 GC_thread p;
3104
3105 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
3106 for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
3107 if (!KNOWN_FINISHED(p)) {
3108 # ifdef DEBUG_THREADS
3109 GC_log_printf("Marking thread locals for 0x%x\n", (int)p -> id);
3110 # endif
3111 GC_mark_thread_local_fls_for(&(p->tlfs));
3112 }
3113 }
3114 }
3115 }
3116
3117 # if defined(GC_ASSERTIONS)
3118 /* Check that all thread-local free-lists are completely marked. */
3119 /* also check that thread-specific-data structures are marked. */
GC_check_tls(void)3120 void GC_check_tls(void)
3121 {
3122 int i;
3123 GC_thread p;
3124
3125 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
3126 for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
3127 if (!KNOWN_FINISHED(p))
3128 GC_check_tls_for(&(p->tlfs));
3129 }
3130 }
3131 # if defined(USE_CUSTOM_SPECIFIC)
3132 if (GC_thread_key != 0)
3133 GC_check_tsd_marks(GC_thread_key);
3134 # endif
3135 }
3136 # endif /* GC_ASSERTIONS */
3137
3138 #endif /* THREAD_LOCAL_ALLOC ... */
3139
3140 # ifndef GC_NO_THREAD_REDIRECTS
3141 /* Restore thread calls redirection. */
3142 # define CreateThread GC_CreateThread
3143 # define ExitThread GC_ExitThread
3144 # undef _beginthreadex
3145 # define _beginthreadex GC_beginthreadex
3146 # undef _endthreadex
3147 # define _endthreadex GC_endthreadex
3148 # endif /* !GC_NO_THREAD_REDIRECTS */
3149
3150 #endif /* GC_WIN32_THREADS */
3151