|
Packit |
d28291 |
/*
|
|
Packit |
d28291 |
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
|
Packit |
d28291 |
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
|
Packit |
d28291 |
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
|
Packit |
d28291 |
* Copyright (c) 2000-2010 by Hewlett-Packard Development Company.
|
|
Packit |
d28291 |
* All rights reserved.
|
|
Packit |
d28291 |
*
|
|
Packit |
d28291 |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
|
Packit |
d28291 |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
|
Packit |
d28291 |
*
|
|
Packit |
d28291 |
* Permission is hereby granted to use or copy this program
|
|
Packit |
d28291 |
* for any purpose, provided the above notices are retained on all copies.
|
|
Packit |
d28291 |
* Permission to modify the code and to distribute modified code is granted,
|
|
Packit |
d28291 |
* provided the above notices are retained, and a notice that the code was
|
|
Packit |
d28291 |
* modified is included with the above copyright notice.
|
|
Packit |
d28291 |
*/
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#include "private/pthread_support.h"
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* This probably needs more porting work to ppc64. */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#if defined(GC_DARWIN_THREADS)
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#include <sys/sysctl.h>
|
|
Packit |
d28291 |
#include <mach/machine.h>
|
|
Packit |
d28291 |
#include <CoreFoundation/CoreFoundation.h>
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
|
|
Packit |
d28291 |
Page 49:
|
|
Packit |
d28291 |
"The space beneath the stack pointer, where a new stack frame would normally
|
|
Packit |
d28291 |
be allocated, is called the red zone. This area as shown in Figure 3-2 may
|
|
Packit |
d28291 |
be used for any purpose as long as a new stack frame does not need to be
|
|
Packit |
d28291 |
added to the stack."
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
|
|
Packit |
d28291 |
it must set up a stack frame just like routines that call other routines."
|
|
Packit |
d28291 |
*/
|
|
Packit |
d28291 |
#ifdef POWERPC
|
|
Packit |
d28291 |
# if CPP_WORDSZ == 32
|
|
Packit |
d28291 |
# define PPC_RED_ZONE_SIZE 224
|
|
Packit |
d28291 |
# elif CPP_WORDSZ == 64
|
|
Packit |
d28291 |
# define PPC_RED_ZONE_SIZE 320
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
#endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
typedef struct StackFrame {
|
|
Packit |
d28291 |
unsigned long savedSP;
|
|
Packit |
d28291 |
unsigned long savedCR;
|
|
Packit |
d28291 |
unsigned long savedLR;
|
|
Packit |
d28291 |
unsigned long reserved[2];
|
|
Packit |
d28291 |
unsigned long savedRTOC;
|
|
Packit |
d28291 |
} StackFrame;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
StackFrame *frame;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef POWERPC
|
|
Packit |
d28291 |
if (stack_start == 0) {
|
|
Packit |
d28291 |
# if CPP_WORDSZ == 32
|
|
Packit |
d28291 |
__asm__ __volatile__ ("lwz %0,0(r1)" : "=r" (frame));
|
|
Packit |
d28291 |
# else
|
|
Packit |
d28291 |
__asm__ __volatile__ ("ld %0,0(r1)" : "=r" (frame));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
} else
|
|
Packit |
d28291 |
# else
|
|
Packit |
d28291 |
GC_ASSERT(stack_start != 0); /* not implemented */
|
|
Packit |
d28291 |
# endif /* !POWERPC */
|
|
Packit |
d28291 |
/* else */ {
|
|
Packit |
d28291 |
frame = (StackFrame *)stack_start;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS_EXTRA
|
|
Packit |
d28291 |
GC_log_printf("FindTopOfStack start at sp = %p\n", (void *)frame);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
while (frame->savedSP != 0) {
|
|
Packit |
d28291 |
/* if there are no more stack frames, stop */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
frame = (StackFrame*)frame->savedSP;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* we do these next two checks after going to the next frame
|
|
Packit |
d28291 |
because the LR for the first stack frame in the loop
|
|
Packit |
d28291 |
is not set up on purpose, so we shouldn't check it. */
|
|
Packit |
d28291 |
if ((frame->savedLR & ~0x3) == 0 || (frame->savedLR & ~0x3) == ~0x3UL)
|
|
Packit |
d28291 |
break; /* if the next LR is bogus, stop */
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS_EXTRA
|
|
Packit |
d28291 |
GC_log_printf("FindTopOfStack finish at sp = %p\n", (void *)frame);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
return (ptr_t)frame;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#endif /* !DARWIN_DONT_PARSE_STACK */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* GC_query_task_threads controls whether to obtain the list of */
|
|
Packit |
d28291 |
/* the threads from the kernel or to use GC_threads table. */
|
|
Packit |
d28291 |
#ifdef GC_NO_THREADS_DISCOVERY
|
|
Packit |
d28291 |
# define GC_query_task_threads FALSE
|
|
Packit |
d28291 |
#elif defined(GC_DISCOVER_TASK_THREADS)
|
|
Packit |
d28291 |
# define GC_query_task_threads TRUE
|
|
Packit |
d28291 |
#else
|
|
Packit |
d28291 |
STATIC GC_bool GC_query_task_threads = FALSE;
|
|
Packit |
d28291 |
#endif /* !GC_NO_THREADS_DISCOVERY */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Use implicit threads registration (all task threads excluding the GC */
|
|
Packit |
d28291 |
/* special ones are stopped and scanned). Should be called before */
|
|
Packit |
d28291 |
/* GC_INIT() (or, at least, before going multi-threaded). Deprecated. */
|
|
Packit |
d28291 |
GC_API void GC_CALL GC_use_threads_discovery(void)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
# if defined(GC_NO_THREADS_DISCOVERY) || defined(DARWIN_DONT_PARSE_STACK)
|
|
Packit |
d28291 |
ABORT("Darwin task-threads-based stop and push unsupported");
|
|
Packit |
d28291 |
# else
|
|
Packit |
d28291 |
# ifndef GC_ALWAYS_MULTITHREADED
|
|
Packit |
d28291 |
GC_ASSERT(!GC_need_to_lock);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
# ifndef GC_DISCOVER_TASK_THREADS
|
|
Packit |
d28291 |
GC_query_task_threads = TRUE;
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
GC_init_parallel(); /* just to be consistent with Win32 one */
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#ifndef kCFCoreFoundationVersionNumber_iOS_8_0
|
|
Packit |
d28291 |
# define kCFCoreFoundationVersionNumber_iOS_8_0 1140.1
|
|
Packit |
d28291 |
#endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Evaluates the stack range for a given thread. Returns the lower */
|
|
Packit |
d28291 |
/* bound and sets *phi to the upper one. */
|
|
Packit |
d28291 |
STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
|
|
Packit |
d28291 |
GC_bool thread_blocked, mach_port_t my_thread,
|
|
Packit |
d28291 |
ptr_t *paltstack_lo,
|
|
Packit |
d28291 |
ptr_t *paltstack_hi GC_ATTR_UNUSED)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
ptr_t lo;
|
|
Packit |
d28291 |
if (thread == my_thread) {
|
|
Packit |
d28291 |
GC_ASSERT(!thread_blocked);
|
|
Packit |
d28291 |
lo = GC_approx_sp();
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = GC_FindTopOfStack(0);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
} else if (thread_blocked) {
|
|
Packit |
d28291 |
# if defined(CPPCHECK)
|
|
Packit |
d28291 |
if (NULL == p) ABORT("Invalid GC_thread passed to GC_stack_range_for");
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
lo = p->stop_info.stack_ptr;
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = p->topOfStack;
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
} else {
|
|
Packit |
d28291 |
/* MACHINE_THREAD_STATE_COUNT does not seem to be defined */
|
|
Packit |
d28291 |
/* everywhere. Hence we use our own version. Alternatively, */
|
|
Packit |
d28291 |
/* we could use THREAD_STATE_MAX (but seems to be not optimal). */
|
|
Packit |
d28291 |
kern_return_t kern_result;
|
|
Packit |
d28291 |
GC_THREAD_STATE_T state;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# if defined(ARM32) && defined(ARM_THREAD_STATE32)
|
|
Packit |
d28291 |
/* Use ARM_UNIFIED_THREAD_STATE on iOS8+ 32-bit targets and on */
|
|
Packit |
d28291 |
/* 64-bit H/W (iOS7+ 32-bit mode). */
|
|
Packit |
d28291 |
size_t size;
|
|
Packit |
d28291 |
static cpu_type_t cputype = 0;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (cputype == 0) {
|
|
Packit |
d28291 |
sysctlbyname("hw.cputype", &cputype, &size, NULL, 0);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
if (cputype == CPU_TYPE_ARM64
|
|
Packit |
d28291 |
|| kCFCoreFoundationVersionNumber
|
|
Packit |
d28291 |
>= kCFCoreFoundationVersionNumber_iOS_8_0) {
|
|
Packit |
d28291 |
arm_unified_thread_state_t unified_state;
|
|
Packit |
d28291 |
mach_msg_type_number_t unified_thread_state_count
|
|
Packit |
d28291 |
= ARM_UNIFIED_THREAD_STATE_COUNT;
|
|
Packit |
d28291 |
# if defined(CPPCHECK)
|
|
Packit |
d28291 |
# define GC_ARM_UNIFIED_THREAD_STATE 1
|
|
Packit |
d28291 |
# else
|
|
Packit |
d28291 |
# define GC_ARM_UNIFIED_THREAD_STATE ARM_UNIFIED_THREAD_STATE
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
kern_result = thread_get_state(thread, GC_ARM_UNIFIED_THREAD_STATE,
|
|
Packit |
d28291 |
(natural_t *)&unified_state,
|
|
Packit |
d28291 |
&unified_thread_state_count);
|
|
Packit |
d28291 |
# if !defined(CPPCHECK)
|
|
Packit |
d28291 |
if (unified_state.ash.flavor != ARM_THREAD_STATE32) {
|
|
Packit |
d28291 |
ABORT("unified_state flavor should be ARM_THREAD_STATE32");
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
state = unified_state.ts_32;
|
|
Packit |
d28291 |
} else
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
/* else */ {
|
|
Packit |
d28291 |
mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Get the thread state (registers, etc) */
|
|
Packit |
d28291 |
kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE,
|
|
Packit |
d28291 |
(natural_t *)&state,
|
|
Packit |
d28291 |
&thread_state_count);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("thread_get_state returns value = %d\n", kern_result);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS)
|
|
Packit |
d28291 |
ABORT("thread_get_state failed");
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# if defined(I386)
|
|
Packit |
d28291 |
lo = (void *)state.THREAD_FLD(esp);
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = GC_FindTopOfStack(state.THREAD_FLD(esp));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(eax));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(ebx));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(ecx));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(edx));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(edi));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(esi));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(ebp));
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# elif defined(X86_64)
|
|
Packit |
d28291 |
lo = (void *)state.THREAD_FLD(rsp);
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = GC_FindTopOfStack(state.THREAD_FLD(rsp));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rax));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rbx));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rcx));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rdx));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rdi));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rsi));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(rbp));
|
|
Packit |
d28291 |
/* GC_push_one(state.THREAD_FLD(rsp)); */
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r8));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r9));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r10));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r11));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r12));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r13));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r14));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r15));
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# elif defined(POWERPC)
|
|
Packit |
d28291 |
lo = (void *)(state.THREAD_FLD(r1) - PPC_RED_ZONE_SIZE);
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = GC_FindTopOfStack(state.THREAD_FLD(r1));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r0));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r2));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r3));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r4));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r5));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r6));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r7));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r8));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r9));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r10));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r11));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r12));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r13));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r14));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r15));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r16));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r17));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r18));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r19));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r20));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r21));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r22));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r23));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r24));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r25));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r26));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r27));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r28));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r29));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r30));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r31));
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# elif defined(ARM32)
|
|
Packit |
d28291 |
lo = (void *)state.THREAD_FLD(sp);
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = GC_FindTopOfStack(state.THREAD_FLD(sp));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
int j;
|
|
Packit |
d28291 |
for (j = 0; j <= 12; j++) {
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(r[j]));
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
/* "pc" and "sp" are skipped */
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(lr));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(cpsr));
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# elif defined(AARCH64)
|
|
Packit |
d28291 |
lo = (void *)state.THREAD_FLD(sp);
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
*phi = GC_FindTopOfStack(state.THREAD_FLD(sp));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
int j;
|
|
Packit |
d28291 |
for (j = 0; j <= 28; j++) {
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(x[j]));
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
/* "cpsr", "pc" and "sp" are skipped */
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(fp));
|
|
Packit |
d28291 |
GC_push_one(state.THREAD_FLD(lr));
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# elif defined(CPPCHECK)
|
|
Packit |
d28291 |
lo = NULL;
|
|
Packit |
d28291 |
# else
|
|
Packit |
d28291 |
# error FIXME for non-x86 || ppc || arm architectures
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
} /* thread != my_thread */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
/* p is guaranteed to be non-NULL regardless of GC_query_task_threads. */
|
|
Packit |
d28291 |
*phi = (p->flags & MAIN_THREAD) != 0 ? GC_stackbottom : p->stack_end;
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* TODO: Determine p and handle altstack if !DARWIN_DONT_PARSE_STACK */
|
|
Packit |
d28291 |
# ifdef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
if (p->altstack != NULL && (word)p->altstack <= (word)lo
|
|
Packit |
d28291 |
&& (word)lo <= (word)p->altstack + p->altstack_size) {
|
|
Packit |
d28291 |
*paltstack_lo = lo;
|
|
Packit |
d28291 |
*paltstack_hi = p->altstack + p->altstack_size;
|
|
Packit |
d28291 |
lo = p->stack;
|
|
Packit |
d28291 |
*phi = p->stack + p->stack_size;
|
|
Packit |
d28291 |
} else
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
/* else */ {
|
|
Packit |
d28291 |
*paltstack_lo = NULL;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Darwin: Stack for thread %p = [%p,%p)\n",
|
|
Packit |
d28291 |
(void *)(word)thread, (void *)lo, (void *)(*phi));
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
return lo;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
GC_INNER void GC_push_all_stacks(void)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
ptr_t hi, altstack_lo, altstack_hi;
|
|
Packit |
d28291 |
task_t my_task = current_task();
|
|
Packit |
d28291 |
mach_port_t my_thread = mach_thread_self();
|
|
Packit |
d28291 |
GC_bool found_me = FALSE;
|
|
Packit |
d28291 |
int nthreads = 0;
|
|
Packit |
d28291 |
word total_size = 0;
|
|
Packit |
d28291 |
mach_msg_type_number_t listcount = (mach_msg_type_number_t)THREAD_TABLE_SZ;
|
|
Packit |
d28291 |
if (!EXPECT(GC_thr_initialized, TRUE))
|
|
Packit |
d28291 |
GC_thr_init();
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifndef DARWIN_DONT_PARSE_STACK
|
|
Packit |
d28291 |
if (GC_query_task_threads) {
|
|
Packit |
d28291 |
int i;
|
|
Packit |
d28291 |
kern_return_t kern_result;
|
|
Packit |
d28291 |
thread_act_array_t act_list = 0;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Obtain the list of the threads from the kernel. */
|
|
Packit |
d28291 |
kern_result = task_threads(my_task, &act_list, &listcount);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS)
|
|
Packit |
d28291 |
ABORT("task_threads failed");
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (i = 0; i < (int)listcount; i++) {
|
|
Packit |
d28291 |
thread_act_t thread = act_list[i];
|
|
Packit |
d28291 |
ptr_t lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread,
|
|
Packit |
d28291 |
&altstack_lo, &altstack_hi);
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (lo) {
|
|
Packit |
d28291 |
GC_ASSERT((word)lo <= (word)hi);
|
|
Packit |
d28291 |
total_size += hi - lo;
|
|
Packit |
d28291 |
GC_push_all_stack(lo, hi);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
/* TODO: Handle altstack */
|
|
Packit |
d28291 |
nthreads++;
|
|
Packit |
d28291 |
if (thread == my_thread)
|
|
Packit |
d28291 |
found_me = TRUE;
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, thread);
|
|
Packit |
d28291 |
} /* for (i=0; ...) */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
vm_deallocate(my_task, (vm_address_t)act_list,
|
|
Packit |
d28291 |
sizeof(thread_t) * listcount);
|
|
Packit |
d28291 |
} else
|
|
Packit |
d28291 |
# endif /* !DARWIN_DONT_PARSE_STACK */
|
|
Packit |
d28291 |
/* else */ {
|
|
Packit |
d28291 |
int i;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (i = 0; i < (int)listcount; i++) {
|
|
Packit |
d28291 |
GC_thread p;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (p = GC_threads[i]; p != NULL; p = p->next)
|
|
Packit |
d28291 |
if ((p->flags & FINISHED) == 0) {
|
|
Packit |
d28291 |
thread_act_t thread = (thread_act_t)p->stop_info.mach_thread;
|
|
Packit |
d28291 |
ptr_t lo = GC_stack_range_for(&hi, thread, p,
|
|
Packit |
d28291 |
(GC_bool)p->thread_blocked,
|
|
Packit |
d28291 |
my_thread, &altstack_lo,
|
|
Packit |
d28291 |
&altstack_hi);
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (lo) {
|
|
Packit |
d28291 |
GC_ASSERT((word)lo <= (word)hi);
|
|
Packit |
d28291 |
total_size += hi - lo;
|
|
Packit |
d28291 |
GC_push_all_stack_sections(lo, hi, p->traced_stack_sect);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
if (altstack_lo) {
|
|
Packit |
d28291 |
total_size += altstack_hi - altstack_lo;
|
|
Packit |
d28291 |
GC_push_all_stack(altstack_lo, altstack_hi);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
nthreads++;
|
|
Packit |
d28291 |
if (thread == my_thread)
|
|
Packit |
d28291 |
found_me = TRUE;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
} /* for (i=0; ...) */
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, my_thread);
|
|
Packit |
d28291 |
GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n", nthreads);
|
|
Packit |
d28291 |
if (!found_me && !GC_in_thread_creation)
|
|
Packit |
d28291 |
ABORT("Collecting from unknown thread");
|
|
Packit |
d28291 |
GC_total_stacksize = total_size;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#ifndef GC_NO_THREADS_DISCOVERY
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef MPROTECT_VDB
|
|
Packit |
d28291 |
STATIC mach_port_t GC_mach_handler_thread = 0;
|
|
Packit |
d28291 |
STATIC GC_bool GC_use_mach_handler_thread = FALSE;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
GC_mach_handler_thread = thread;
|
|
Packit |
d28291 |
GC_use_mach_handler_thread = TRUE;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# endif /* MPROTECT_VDB */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifndef GC_MAX_MACH_THREADS
|
|
Packit |
d28291 |
# define GC_MAX_MACH_THREADS THREAD_TABLE_SZ
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
struct GC_mach_thread {
|
|
Packit |
d28291 |
thread_act_t thread;
|
|
Packit |
d28291 |
GC_bool already_suspended;
|
|
Packit |
d28291 |
};
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
struct GC_mach_thread GC_mach_threads[GC_MAX_MACH_THREADS];
|
|
Packit |
d28291 |
STATIC int GC_mach_threads_count = 0;
|
|
Packit |
d28291 |
/* FIXME: it is better to implement GC_mach_threads as a hash set. */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* returns true if there's a thread in act_list that wasn't in old_list */
|
|
Packit |
d28291 |
STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
|
Packit |
d28291 |
thread_act_array_t old_list,
|
|
Packit |
d28291 |
int old_count, mach_port_t my_thread)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
int i;
|
|
Packit |
d28291 |
int j = -1;
|
|
Packit |
d28291 |
GC_bool changed = FALSE;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (i = 0; i < count; i++) {
|
|
Packit |
d28291 |
thread_act_t thread = act_list[i];
|
|
Packit |
d28291 |
GC_bool found;
|
|
Packit |
d28291 |
struct thread_basic_info info;
|
|
Packit |
d28291 |
mach_msg_type_number_t outCount;
|
|
Packit |
d28291 |
kern_return_t kern_result;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (thread == my_thread
|
|
Packit |
d28291 |
# ifdef MPROTECT_VDB
|
|
Packit |
d28291 |
|| (GC_mach_handler_thread == thread && GC_use_mach_handler_thread)
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
) {
|
|
Packit |
d28291 |
/* Don't add our and the handler threads. */
|
|
Packit |
d28291 |
continue;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# ifdef PARALLEL_MARK
|
|
Packit |
d28291 |
if (GC_is_mach_marker(thread))
|
|
Packit |
d28291 |
continue; /* ignore the parallel marker threads */
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Attempting to suspend thread %p\n",
|
|
Packit |
d28291 |
(void *)(word)thread);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
/* find the current thread in the old list */
|
|
Packit |
d28291 |
found = FALSE;
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
int last_found = j; /* remember the previous found thread index */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Search for the thread starting from the last found one first. */
|
|
Packit |
d28291 |
while (++j < old_count)
|
|
Packit |
d28291 |
if (old_list[j] == thread) {
|
|
Packit |
d28291 |
found = TRUE;
|
|
Packit |
d28291 |
break;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
if (!found) {
|
|
Packit |
d28291 |
/* If not found, search in the rest (beginning) of the list. */
|
|
Packit |
d28291 |
for (j = 0; j < last_found; j++)
|
|
Packit |
d28291 |
if (old_list[j] == thread) {
|
|
Packit |
d28291 |
found = TRUE;
|
|
Packit |
d28291 |
break;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (!found) {
|
|
Packit |
d28291 |
/* add it to the GC_mach_threads list */
|
|
Packit |
d28291 |
if (GC_mach_threads_count == GC_MAX_MACH_THREADS)
|
|
Packit |
d28291 |
ABORT("Too many threads");
|
|
Packit |
d28291 |
GC_mach_threads[GC_mach_threads_count].thread = thread;
|
|
Packit |
d28291 |
/* default is not suspended */
|
|
Packit |
d28291 |
GC_mach_threads[GC_mach_threads_count].already_suspended = FALSE;
|
|
Packit |
d28291 |
changed = TRUE;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
outCount = THREAD_INFO_MAX;
|
|
Packit |
d28291 |
kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
|
Packit |
d28291 |
(thread_info_t)&info, &outCount);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS) {
|
|
Packit |
d28291 |
/* The thread may have quit since the thread_threads() call we */
|
|
Packit |
d28291 |
/* mark already suspended so it's not dealt with anymore later. */
|
|
Packit |
d28291 |
if (!found)
|
|
Packit |
d28291 |
GC_mach_threads[GC_mach_threads_count++].already_suspended = TRUE;
|
|
Packit |
d28291 |
continue;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Thread state for %p = %d\n", (void *)(word)thread,
|
|
Packit |
d28291 |
info.run_state);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
if (info.suspend_count != 0) {
|
|
Packit |
d28291 |
/* thread is already suspended. */
|
|
Packit |
d28291 |
if (!found)
|
|
Packit |
d28291 |
GC_mach_threads[GC_mach_threads_count++].already_suspended = TRUE;
|
|
Packit |
d28291 |
continue;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Suspending %p\n", (void *)(word)thread);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
kern_result = thread_suspend(thread);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS) {
|
|
Packit |
d28291 |
/* The thread may have quit since the thread_threads() call we */
|
|
Packit |
d28291 |
/* mark already suspended so it's not dealt with anymore later. */
|
|
Packit |
d28291 |
if (!found)
|
|
Packit |
d28291 |
GC_mach_threads[GC_mach_threads_count++].already_suspended = TRUE;
|
|
Packit |
d28291 |
continue;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
if (!found)
|
|
Packit |
d28291 |
GC_mach_threads_count++;
|
|
Packit |
d28291 |
if (GC_on_thread_event)
|
|
Packit |
d28291 |
GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)(word)thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
return changed;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#endif /* !GC_NO_THREADS_DISCOVERY */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Caller holds allocation lock. */
|
|
Packit |
d28291 |
GC_INNER void GC_stop_world(void)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
task_t my_task = current_task();
|
|
Packit |
d28291 |
mach_port_t my_thread = mach_thread_self();
|
|
Packit |
d28291 |
kern_return_t kern_result;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Stopping the world from thread %p\n",
|
|
Packit |
d28291 |
(void *)(word)my_thread);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
# ifdef PARALLEL_MARK
|
|
Packit |
d28291 |
if (GC_parallel) {
|
|
Packit |
d28291 |
/* Make sure all free list construction has stopped before we */
|
|
Packit |
d28291 |
/* start. No new construction can start, since free list */
|
|
Packit |
d28291 |
/* construction is required to acquire and release the GC lock */
|
|
Packit |
d28291 |
/* before it starts, and we have the lock. */
|
|
Packit |
d28291 |
GC_acquire_mark_lock();
|
|
Packit |
d28291 |
GC_ASSERT(GC_fl_builder_count == 0);
|
|
Packit |
d28291 |
/* We should have previously waited for it to become zero. */
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# endif /* PARALLEL_MARK */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (GC_query_task_threads) {
|
|
Packit |
d28291 |
# ifndef GC_NO_THREADS_DISCOVERY
|
|
Packit |
d28291 |
unsigned i;
|
|
Packit |
d28291 |
GC_bool changed;
|
|
Packit |
d28291 |
thread_act_array_t act_list, prev_list;
|
|
Packit |
d28291 |
mach_msg_type_number_t listcount, prevcount;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Clear out the mach threads list table. We do not need to */
|
|
Packit |
d28291 |
/* really clear GC_mach_threads[] as it is used only in the range */
|
|
Packit |
d28291 |
/* from 0 to GC_mach_threads_count-1, inclusive. */
|
|
Packit |
d28291 |
GC_mach_threads_count = 0;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Loop stopping threads until you have gone over the whole list */
|
|
Packit |
d28291 |
/* twice without a new one appearing. thread_create() won't */
|
|
Packit |
d28291 |
/* return (and thus the thread stop) until the new thread exists, */
|
|
Packit |
d28291 |
/* so there is no window whereby you could stop a thread, */
|
|
Packit |
d28291 |
/* recognize it is stopped, but then have a new thread it created */
|
|
Packit |
d28291 |
/* before stopping show up later. */
|
|
Packit |
d28291 |
changed = TRUE;
|
|
Packit |
d28291 |
prev_list = NULL;
|
|
Packit |
d28291 |
prevcount = 0;
|
|
Packit |
d28291 |
do {
|
|
Packit |
d28291 |
kern_result = task_threads(my_task, &act_list, &listcount);
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (kern_result == KERN_SUCCESS) {
|
|
Packit |
d28291 |
changed = GC_suspend_thread_list(act_list, listcount, prev_list,
|
|
Packit |
d28291 |
prevcount, my_thread);
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (prev_list != NULL) {
|
|
Packit |
d28291 |
for (i = 0; i < prevcount; i++)
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, prev_list[i]);
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
vm_deallocate(my_task, (vm_address_t)prev_list,
|
|
Packit |
d28291 |
sizeof(thread_t) * prevcount);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Repeat while having changes. */
|
|
Packit |
d28291 |
prev_list = act_list;
|
|
Packit |
d28291 |
prevcount = listcount;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
} while (changed);
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
GC_ASSERT(prev_list != 0);
|
|
Packit |
d28291 |
for (i = 0; i < prevcount; i++)
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, prev_list[i]);
|
|
Packit |
d28291 |
vm_deallocate(my_task, (vm_address_t)act_list,
|
|
Packit |
d28291 |
sizeof(thread_t) * listcount);
|
|
Packit |
d28291 |
# endif /* !GC_NO_THREADS_DISCOVERY */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
} else {
|
|
Packit |
d28291 |
unsigned i;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
|
Packit |
d28291 |
GC_thread p;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (p = GC_threads[i]; p != NULL; p = p->next) {
|
|
Packit |
d28291 |
if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
|
|
Packit |
d28291 |
p->stop_info.mach_thread != my_thread) {
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
kern_result = thread_suspend(p->stop_info.mach_thread);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS)
|
|
Packit |
d28291 |
ABORT("thread_suspend failed");
|
|
Packit |
d28291 |
if (GC_on_thread_event)
|
|
Packit |
d28291 |
GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
|
|
Packit |
d28291 |
(void *)(word)p->stop_info.mach_thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef MPROTECT_VDB
|
|
Packit |
d28291 |
if(GC_incremental) {
|
|
Packit |
d28291 |
GC_mprotect_stop();
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
# ifdef PARALLEL_MARK
|
|
Packit |
d28291 |
if (GC_parallel)
|
|
Packit |
d28291 |
GC_release_mark_lock();
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("World stopped from %p\n", (void *)(word)my_thread);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, my_thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
GC_INLINE void GC_thread_resume(thread_act_t thread)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
kern_return_t kern_result;
|
|
Packit |
d28291 |
# if defined(DEBUG_THREADS) || defined(GC_ASSERTIONS)
|
|
Packit |
d28291 |
struct thread_basic_info info;
|
|
Packit |
d28291 |
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
|
Packit |
d28291 |
kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
|
Packit |
d28291 |
(thread_info_t)&info, &outCount);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS)
|
|
Packit |
d28291 |
ABORT("thread_info failed");
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Resuming thread %p with state %d\n", (void *)(word)thread,
|
|
Packit |
d28291 |
info.run_state);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
/* Resume the thread */
|
|
Packit |
d28291 |
kern_result = thread_resume(thread);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS)
|
|
Packit |
d28291 |
ABORT("thread_resume failed");
|
|
Packit |
d28291 |
if (GC_on_thread_event)
|
|
Packit |
d28291 |
GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)(word)thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Caller holds allocation lock, and has held it continuously since */
|
|
Packit |
d28291 |
/* the world stopped. */
|
|
Packit |
d28291 |
GC_INNER void GC_start_world(void)
|
|
Packit |
d28291 |
{
|
|
Packit |
d28291 |
task_t my_task = current_task();
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("World starting\n");
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
# ifdef MPROTECT_VDB
|
|
Packit |
d28291 |
if(GC_incremental) {
|
|
Packit |
d28291 |
GC_mprotect_resume();
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (GC_query_task_threads) {
|
|
Packit |
d28291 |
# ifndef GC_NO_THREADS_DISCOVERY
|
|
Packit |
d28291 |
int i;
|
|
Packit |
d28291 |
int j = GC_mach_threads_count;
|
|
Packit |
d28291 |
kern_return_t kern_result;
|
|
Packit |
d28291 |
thread_act_array_t act_list;
|
|
Packit |
d28291 |
mach_msg_type_number_t listcount;
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
kern_result = task_threads(my_task, &act_list, &listcount);
|
|
Packit |
d28291 |
if (kern_result != KERN_SUCCESS)
|
|
Packit |
d28291 |
ABORT("task_threads failed");
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (i = 0; i < (int)listcount; i++) {
|
|
Packit |
d28291 |
thread_act_t thread = act_list[i];
|
|
Packit |
d28291 |
int last_found = j; /* The thread index found during the */
|
|
Packit |
d28291 |
/* previous iteration (count value */
|
|
Packit |
d28291 |
/* means no thread found yet). */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
/* Search for the thread starting from the last found one first. */
|
|
Packit |
d28291 |
while (++j < GC_mach_threads_count) {
|
|
Packit |
d28291 |
if (GC_mach_threads[j].thread == thread)
|
|
Packit |
d28291 |
break;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
if (j >= GC_mach_threads_count) {
|
|
Packit |
d28291 |
/* If not found, search in the rest (beginning) of the list. */
|
|
Packit |
d28291 |
for (j = 0; j < last_found; j++) {
|
|
Packit |
d28291 |
if (GC_mach_threads[j].thread == thread)
|
|
Packit |
d28291 |
break;
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
if (j != last_found) {
|
|
Packit |
d28291 |
/* The thread is found in GC_mach_threads. */
|
|
Packit |
d28291 |
if (GC_mach_threads[j].already_suspended) {
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("Not resuming already suspended thread %p\n",
|
|
Packit |
d28291 |
(void *)(word)thread);
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
} else {
|
|
Packit |
d28291 |
GC_thread_resume(thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
vm_deallocate(my_task, (vm_address_t)act_list,
|
|
Packit |
d28291 |
sizeof(thread_t) * listcount);
|
|
Packit |
d28291 |
# endif /* !GC_NO_THREADS_DISCOVERY */
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
} else {
|
|
Packit |
d28291 |
int i;
|
|
Packit |
d28291 |
mach_port_t my_thread = mach_thread_self();
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
|
Packit |
d28291 |
GC_thread p;
|
|
Packit |
d28291 |
for (p = GC_threads[i]; p != NULL; p = p->next) {
|
|
Packit |
d28291 |
if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
|
|
Packit |
d28291 |
p->stop_info.mach_thread != my_thread)
|
|
Packit |
d28291 |
GC_thread_resume(p->stop_info.mach_thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
mach_port_deallocate(my_task, my_thread);
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
# ifdef DEBUG_THREADS
|
|
Packit |
d28291 |
GC_log_printf("World started\n");
|
|
Packit |
d28291 |
# endif
|
|
Packit |
d28291 |
}
|
|
Packit |
d28291 |
|
|
Packit |
d28291 |
#endif /* GC_DARWIN_THREADS */
|