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