Exemplo n.º 1
0
/* This callback handles starting execution of a thread. */
static void start_thread(void *data) {
    ThreadStart *ts = (ThreadStart *)data;
    MVMThreadContext *tc = ts->tc;

    /* Set the current frame in the thread to be the initial caller;
     * the ref count for this was incremented in the original thread. */
    tc->cur_frame = ts->caller;

    /* wait for the GC to finish if it's not finished stealing us. */
    MVM_gc_mark_thread_unblocked(tc);
    tc->thread_obj->body.stage = MVM_thread_stage_started;

    /* Enter the interpreter, to run code. */
    MVM_interp_run(tc, &thread_initial_invoke, ts);

    /* mark as exited, so the GC will know to clear our stuff. */
    tc->thread_obj->body.stage = MVM_thread_stage_exited;

    /* Now we're done, decrement the reference count of the caller. */
    MVM_frame_dec_ref(tc, ts->caller);

    /* Mark ourselves as dying, so that another thread will take care
     * of GC-ing our objects and cleaning up our thread context. */
    MVM_gc_mark_thread_blocked(tc);

    /* hopefully pop the ts->thread_obj temp */
    MVM_gc_root_temp_pop(tc);
    free(ts);

    /* Exit the thread, now it's completed. */
    MVM_platform_thread_exit(NULL);
}
Exemplo n.º 2
0
Arquivo: ops.c Projeto: bingos/MoarVM
MVMString * MVM_string_repeat(MVMThreadContext *tc, MVMString *a, MVMint64 count) {
    MVMString *result;
    MVMint64 bkup_count = count;
    MVMStringIndex string_offset = 0, graphs = 0, rgraphs;
    
    if (!IS_CONCRETE((MVMObject *)a)) {
        MVM_exception_throw_adhoc(tc, "repeat needs a concrete string");
    }
    
    if (count < 0)
        MVM_exception_throw_adhoc(tc, "repeat count (%lld) cannot be negative", count);
    
    if (count > (1<<30))
        MVM_exception_throw_adhoc(tc, "repeat count > %lld arbitrarily unsupported...", (1<<30));
    
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&a);
    result = (MVMString *)REPR(a)->allocate(tc, STABLE(a));
    MVM_gc_root_temp_pop(tc);
    
    if (IS_ONE_STRING_ROPE(a)) {
        string_offset = a->body.strands->string_offset;
        graphs = a->body.strands[1].graphs;
        a = a->body.strands->string;
    }
    else {
        graphs = NUM_GRAPHS(a);
    }
    
    rgraphs = graphs * count;
    
    /* XXX compute tradeoff here of space usage of the strands table vs real string */
    if (rgraphs) {
        MVMStrand *strands = result->body.strands = calloc(sizeof(MVMStrand), count + 1);
        result->body.flags = MVM_STRING_TYPE_ROPE;
        
        while (count--) {
            strands[count].compare_offset = count * graphs;
            strands[count].string = a;
            strands[count].string_offset = string_offset;
        }
        strands[bkup_count].graphs = rgraphs;
        result->body.num_strands = bkup_count;
        _STRAND_DEPTH(result) = STRAND_DEPTH(a) + 1;
    }
    else {
        result->body.flags = MVM_STRING_TYPE_UINT8;
        /* leave graphs 0 and storage null */
    }
    
    return result;
}
Exemplo n.º 3
0
Arquivo: ops.c Projeto: bingos/MoarVM
/* XXX inline parent's strands if it's a rope too? */
MVMString * MVM_string_concatenate(MVMThreadContext *tc, MVMString *a, MVMString *b) {
    MVMString *result;
    MVMStrandIndex strand_count = 0;
    MVMStrand *strands;
    MVMStringIndex index = 0;
    MVMStrandIndex max_strand_depth = 0;
    MVMStringIndex agraphs = NUM_GRAPHS(a), bgraphs = NUM_GRAPHS(b), rgraphs;
    
    if (!IS_CONCRETE((MVMObject *)a) || !IS_CONCRETE((MVMObject *)b)) {
        MVM_exception_throw_adhoc(tc, "Concatenate needs concrete strings");
    }
    
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&a);
    result = (MVMString *)REPR(a)->allocate(tc, STABLE(a));
    MVM_gc_root_temp_pop(tc);
    
    /* there could be unattached combining chars at the beginning of b,
       so, XXX TODO handle this */
    result->body.flags = MVM_STRING_TYPE_ROPE;
    rgraphs = agraphs + bgraphs;
    
    if (agraphs)
        strand_count = 1;
    if (bgraphs)
        ++strand_count;
    strands = result->body.strands = calloc(sizeof(MVMStrand), strand_count + 1);
    strand_count = 0;
    if (agraphs) {
        strands->string = a;
        strands->string_offset = 0;
        strands->compare_offset = index;
        index = agraphs;
        strand_count = 1;
        max_strand_depth = STRAND_DEPTH(a);
    }
    if (bgraphs) {
        strands[strand_count].string = b;
        strands[strand_count].string_offset = 0;
        strands[strand_count].compare_offset = index;
        index += bgraphs;
        ++strand_count;
        if (STRAND_DEPTH(b) > max_strand_depth)
            max_strand_depth = STRAND_DEPTH(b);
    }
    strands[strand_count].graphs = index;
    result->body.num_strands = strand_count;
    result->body.flags = MVM_STRING_TYPE_ROPE;
    _STRAND_DEPTH(result) = max_strand_depth + 1;
    
    return result;
}
Exemplo n.º 4
0
Arquivo: ops.c Projeto: bingos/MoarVM
/* Returns a substring of the given string */
MVMString * MVM_string_substring(MVMThreadContext *tc, MVMString *a, MVMint64 start, MVMint64 length) {
    MVMString *result;
    MVMStrand *strands;
    MVMStringIndex agraphs = NUM_GRAPHS(a);
    
    if (start < 0) {
        start += agraphs;
        if (start < 0)
            start = 0;
    }
    
    if (!IS_CONCRETE((MVMObject *)a)) {
        MVM_exception_throw_adhoc(tc, "Substring needs a concrete string");
    }
    
    if (start > agraphs)
        start = agraphs;
        
    if (length == -1) /* -1 signifies go to the end of the string */
        length = agraphs - start;
    
    if (length < 0)
        MVM_exception_throw_adhoc(tc, "Substring length (%lld) cannot be negative", length);
    
    if (start + length > agraphs)
        length = agraphs - start;
    
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&a);
    result = (MVMString *)REPR(a)->allocate(tc, STABLE(a));
    MVM_gc_root_temp_pop(tc);
    
    strands = result->body.strands = calloc(sizeof(MVMStrand), 2);
    /* if we're substringing a substring, substring the same one */
    if (IS_ONE_STRING_ROPE(a)) {
        strands->string_offset = (MVMStringIndex)start + a->body.strands->string_offset;
        strands->string = a->body.strands->string;
    }
    else {
        strands->string_offset = (MVMStringIndex)start;
        strands->string = a;
    }
    /* result->body.codes  = 0; /* Populate this lazily. */
    result->body.flags = MVM_STRING_TYPE_ROPE;
    result->body.num_strands = 1;
    strands[1].graphs = length;
    _STRAND_DEPTH(result) = STRAND_DEPTH(strands->string) + 1;
    
    return result;
}
Exemplo n.º 5
0
void MVM_thread_join(MVMThreadContext *tc, MVMObject *thread_obj) {
    if (REPR(thread_obj)->ID == MVM_REPR_ID_MVMThread) {
        MVMThread *thread = (MVMThread *)thread_obj;
        int status;
        MVM_gc_root_temp_push(tc, (MVMCollectable **)&thread);
        MVM_gc_mark_thread_blocked(tc);
        if (((MVMThread *)thread_obj)->body.stage < MVM_thread_stage_exited) {
            status = uv_thread_join(&thread->body.thread);
        }
        else { /* the target already ended */
            /* used to be APR_SUCCESS, but then we ditched APR */
            status = 0;
        }
        MVM_gc_mark_thread_unblocked(tc);
        MVM_gc_root_temp_pop(tc);
        if (status < 0)
            MVM_panic(MVM_exitcode_compunit, "Could not join thread: errorcode %d", status);
    }
    else {
        MVM_exception_throw_adhoc(tc,
            "Thread handle passed to join must have representation MVMThread");
    }
}
Exemplo n.º 6
0
MVMObject * MVM_thread_start(MVMThreadContext *tc, MVMObject *invokee, MVMObject *result_type) {
    int status;
    ThreadStart *ts;
    MVMObject *child_obj;

    /* Create a thread object to wrap it up in. */
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&invokee);
    child_obj = REPR(result_type)->allocate(tc, STABLE(result_type));
    MVM_gc_root_temp_pop(tc);
    if (REPR(child_obj)->ID == MVM_REPR_ID_MVMThread) {
        MVMThread *child = (MVMThread *)child_obj;
        MVMThread * volatile *threads;

        /* Create a new thread context and set it up. */
        MVMThreadContext *child_tc = MVM_tc_create(tc->instance);
        child->body.tc = child_tc;
        MVM_ASSIGN_REF(tc, child, child->body.invokee, invokee);
        child_tc->thread_obj = child;
        child_tc->thread_id = MVM_incr(&tc->instance->next_user_thread_id);

        /* Create the thread. Note that we take a reference to the current frame,
         * since it must survive to be the dynamic scope of where the thread was
         * started, and there's no promises that the thread won't start before
         * the code creating the thread returns. The count is decremented when
         * the thread is done. */
        ts = malloc(sizeof(ThreadStart));
        ts->tc = child_tc;
        ts->caller = MVM_frame_inc_ref(tc, tc->cur_frame);
        ts->thread_obj = child_obj;

        /* push this to the *child* tc's temp roots. */
        MVM_gc_root_temp_push(child_tc, (MVMCollectable **)&ts->thread_obj);

        /* Signal to the GC we have a childbirth in progress. The GC
         * will null it for us. */
        MVM_gc_mark_thread_blocked(child_tc);
        MVM_ASSIGN_REF(tc, tc->thread_obj, tc->thread_obj->body.new_child, child);

        /* push to starting threads list */
        threads = &tc->instance->threads;
        do {
            MVMThread *curr = *threads;
            MVM_ASSIGN_REF(tc, child, child->body.next, curr);
        } while (MVM_casptr(threads, child->body.next, child) != child->body.next);


        status = uv_thread_create(&child->body.thread, &start_thread, ts);

        if (status < 0) {
            MVM_panic(MVM_exitcode_compunit, "Could not spawn thread: errorcode %d", status);
        }

        /* need to run the GC to clear our new_child field in case we try
         * try to launch another thread before the GC runs and before the
         * thread starts. */
        GC_SYNC_POINT(tc);
    }
    else {
        MVM_exception_throw_adhoc(tc,
            "Thread result type must have representation MVMThread");
    }

    return child_obj;
}