static void jl_ast_ctx_leave(jl_ast_context_t *ctx) { JL_SIGATOMIC_END(); if (--ctx->ref) return; JL_LOCK_NOGC(&flisp_lock); ctx->task = NULL; jl_ast_context_list_t *node = &ctx->list; jl_ast_context_list_delete(node); jl_ast_context_list_insert(&jl_ast_ctx_freed, node); JL_UNLOCK_NOGC(&flisp_lock); }
void jl_mach_gc_end(void) { JL_LOCK_NOGC(gc_suspend); jl_gc_safepoint_activated = 0; for (size_t i = 0;i < suspended_threads.len;i++) { uintptr_t item = (uintptr_t)suspended_threads.items[i]; int16_t tid = (int16_t)item; int8_t gc_state = (int8_t)(item >> 8); jl_all_task_states[tid].ptls->gc_state = gc_state; thread_resume(pthread_mach_thread_np(jl_all_task_states[tid].system_id)); } suspended_threads.len = 0; JL_UNLOCK_NOGC(gc_suspend); }
static jl_sym_t *_jl_symbol(const char *str, size_t len) { jl_sym_t *volatile *slot; jl_sym_t *node = symtab_lookup(&symtab, str, len, &slot); if (node == NULL) { JL_LOCK_NOGC(&gc_perm_lock); // Someone might have updated it, check and look up again if (*slot != NULL && (node = symtab_lookup(slot, str, len, &slot))) { JL_UNLOCK_NOGC(&gc_perm_lock); return node; } node = mk_symbol(str, len); jl_atomic_store_release(slot, node); JL_UNLOCK_NOGC(&gc_perm_lock); } return node; }
static jl_ast_context_t *jl_ast_ctx_enter(void) { jl_ptls_t ptls = jl_get_ptls_states(); JL_SIGATOMIC_BEGIN(); JL_LOCK_NOGC(&flisp_lock); jl_ast_context_list_t *node; jl_ast_context_t *ctx; // First check if the current task is using one of the contexts for (node = jl_ast_ctx_using;node;(node = node->next)) { ctx = jl_ast_context_list_item(node); if (ctx->task == ptls->current_task) { ctx->ref++; JL_UNLOCK_NOGC(&flisp_lock); return ctx; } } // If not, grab one from the free list if ((node = jl_ast_ctx_freed)) { jl_ast_context_list_delete(node); jl_ast_context_list_insert(&jl_ast_ctx_using, node); ctx = jl_ast_context_list_item(node); ctx->ref = 1; ctx->task = ptls->current_task; ctx->module = NULL; JL_UNLOCK_NOGC(&flisp_lock); return ctx; } // Construct a new one if we can't find any ctx = (jl_ast_context_t*)calloc(1, sizeof(jl_ast_context_t)); ctx->ref = 1; ctx->task = ptls->current_task; node = &ctx->list; jl_ast_context_list_insert(&jl_ast_ctx_using, node); JL_UNLOCK_NOGC(&flisp_lock); jl_init_ast_ctx(ctx); return ctx; }
void jl_mach_gc_begin(void) { JL_LOCK_NOGC(gc_suspend); jl_gc_safepoint_activated = 1; JL_UNLOCK_NOGC(gc_suspend); }
//exc_server uses dlsym to find symbol JL_DLLEXPORT kern_return_t catch_exception_raise(mach_port_t exception_port, mach_port_t thread, mach_port_t task, exception_type_t exception, exception_data_t code, mach_msg_type_number_t code_count) { unsigned int count = MACHINE_THREAD_STATE_COUNT; unsigned int exc_count = X86_EXCEPTION_STATE64_COUNT; x86_exception_state64_t exc_state; x86_thread_state64_t state; #ifdef LIBOSXUNWIND if (thread == mach_profiler_thread) { return profiler_segv_handler(exception_port, thread, task, exception, code, code_count); } #endif int16_t tid; #ifdef JULIA_ENABLE_THREADING jl_tls_states_t *ptls = NULL; for (tid = 0;tid < jl_n_threads;tid++) { if (pthread_mach_thread_np(jl_all_task_states[tid].system_id) == thread) { ptls = jl_all_task_states[tid].ptls; break; } } if (!ptls) { // We don't know about this thread, let the kernel try another handler // instead. This shouldn't actually happen since we only register the // handler for the threads we know about. jl_safe_printf("ERROR: Exception handler triggered on unmanaged thread.\n"); return KERN_INVALID_ARGUMENT; } #else jl_tls_states_t *ptls = &jl_tls_states; tid = 0; #endif kern_return_t ret = thread_get_state(thread, x86_EXCEPTION_STATE64, (thread_state_t)&exc_state, &exc_count); HANDLE_MACH_ERROR("thread_get_state", ret); uint64_t fault_addr = exc_state.__faultvaddr; #ifdef JULIA_ENABLE_THREADING if (fault_addr == (uintptr_t)jl_gc_signal_page) { JL_LOCK_NOGC(gc_suspend); if (!jl_gc_safepoint_activated) { // GC is done before we get the message, do nothing and return JL_UNLOCK_NOGC(gc_suspend); return KERN_SUCCESS; } // Otherwise, set the gc state of the thread, suspend and record it int8_t gc_state = ptls->gc_state; ptls->gc_state = JL_GC_STATE_WAITING; uintptr_t item = tid | (((uintptr_t)gc_state) << 16); arraylist_push(&suspended_threads, (void*)item); thread_suspend(thread); JL_UNLOCK_NOGC(gc_suspend); return KERN_SUCCESS; } #endif #ifdef SEGV_EXCEPTION if (1) { #else if (msync((void*)(fault_addr & ~(jl_page_size - 1)), 1, MS_ASYNC) == 0) { // check if this was a valid address #endif jl_value_t *excpt; if (is_addr_on_stack(ptls, (void*)fault_addr)) { excpt = jl_stackovf_exception; } #ifdef SEGV_EXCEPTION else if (msync((void*)(fault_addr & ~(jl_page_size - 1)), 1, MS_ASYNC) != 0) { // no page mapped at this address excpt = jl_segv_exception; } #endif else { if (!(exc_state.__err & WRITE_FAULT)) return KERN_INVALID_ARGUMENT; // rethrow the SEGV since it wasn't an error with writing to read-only memory excpt = jl_readonlymemory_exception; } jl_throw_in_thread(tid, thread, excpt); return KERN_SUCCESS; } else { kern_return_t ret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&state, &count); HANDLE_MACH_ERROR("thread_get_state", ret); jl_critical_error(SIGSEGV, (unw_context_t*)&state, ptls->bt_data, &ptls->bt_size); return KERN_INVALID_ARGUMENT; } } static void attach_exception_port(thread_port_t thread) { kern_return_t ret; // http://www.opensource.apple.com/source/xnu/xnu-2782.1.97/osfmk/man/thread_set_exception_ports.html ret = thread_set_exception_ports(thread, EXC_MASK_BAD_ACCESS, segv_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE); HANDLE_MACH_ERROR("thread_set_exception_ports", ret); }