Beispiel #1
0
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);
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
void jl_mach_gc_begin(void)
{
    JL_LOCK_NOGC(gc_suspend);
    jl_gc_safepoint_activated = 1;
    JL_UNLOCK_NOGC(gc_suspend);
}
Beispiel #6
0
//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);
}