Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/core/threadcontext.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include "platform/time.h"
3
4
/* Initializes a new thread context. Note that this doesn't set up a
5
 * thread itself, it just creates the data structure that exists in
6
 * MoarVM per thread. */
7
317
MVMThreadContext * MVM_tc_create(MVMThreadContext *parent, MVMInstance *instance) {
8
317
    MVMThreadContext *tc = MVM_calloc(1, sizeof(MVMThreadContext));
9
317
10
317
    /* Associate with VM instance. */
11
317
    tc->instance = instance;
12
317
13
317
    /* Use default loop for main thread; create a new one for others. */
14
317
    if (instance->main_thread) {
15
173
        int r;
16
173
17
173
        tc->loop = MVM_calloc(1, sizeof(uv_loop_t));
18
173
        r = uv_loop_init(tc->loop);
19
173
        if (r < 0) {
20
0
            MVM_free(tc->loop);
21
0
            MVM_free(tc);
22
0
            MVM_exception_throw_adhoc(parent, "Could not create a new Thread: %s", uv_strerror(r));
23
0
        }
24
144
    } else {
25
144
        tc->loop = uv_default_loop();
26
144
    }
27
317
28
317
    /* Set up GC nursery. We only allocate tospace initially, and allocate
29
317
     * fromspace the first time this thread GCs, provided it ever does. */
30
317
    tc->nursery_tospace_size = MVM_gc_new_thread_nursery_size(instance);
31
317
    tc->nursery_tospace     = MVM_calloc(1, tc->nursery_tospace_size);
32
317
    tc->nursery_alloc       = tc->nursery_tospace;
33
317
    tc->nursery_alloc_limit = (char *)tc->nursery_alloc + tc->nursery_tospace_size;
34
317
35
317
    /* Set up temporary root handling. */
36
317
    tc->num_temproots   = 0;
37
317
    tc->alloc_temproots = MVM_TEMP_ROOT_BASE_ALLOC;
38
317
    tc->temproots       = MVM_malloc(sizeof(MVMCollectable **) * tc->alloc_temproots);
39
317
40
317
    /* Set up intergenerational root handling. */
41
317
    tc->num_gen2roots   = 0;
42
317
    tc->alloc_gen2roots = 64;
43
317
    tc->gen2roots       = MVM_malloc(sizeof(MVMCollectable *) * tc->alloc_gen2roots);
44
317
45
317
    /* Set up the second generation allocator. */
46
317
    tc->gen2 = MVM_gc_gen2_create(instance);
47
317
48
317
    /* The fixed size allocator also keeps pre-thread state. */
49
317
    MVM_fixed_size_create_thread(tc);
50
317
51
317
    /* Allocate an initial call stack region for the thread. */
52
317
    MVM_callstack_region_init(tc);
53
317
54
317
    /* Initialize random number generator state. */
55
317
    MVM_proc_seed(tc, (MVM_platform_now() / 10000) * MVM_proc_getpid(tc));
56
317
57
317
    /* Initialize frame sequence numbers */
58
317
    tc->next_frame_nr = 0;
59
317
    tc->current_frame_nr = 0;
60
317
61
317
    /* Initialize last_payload, so we can be sure it's never NULL and don't
62
317
     * need to check. */
63
317
    tc->last_payload = instance->VMNull;
64
317
65
317
    return tc;
66
317
}
67
68
/* Destroys a given thread context. This will also free the nursery.
69
 * This means that it must no longer be in use, at all; this can be
70
 * ensured by a GC run at thread exit that forces evacuation of all
71
 * objects from this nursery to the second generation. Only after
72
 * that is true should this be called. */
73
23
void MVM_tc_destroy(MVMThreadContext *tc) {
74
23
    /* We run once again (non-blocking) to eventually close filehandles. */
75
23
    uv_run(tc->loop, UV_RUN_NOWAIT);
76
23
77
23
    /* Free specialization state. */
78
23
    MVM_spesh_sim_stack_destroy(tc, tc->spesh_sim_stack);
79
23
80
23
    /* Free the nursery and finalization queue. */
81
23
    MVM_free(tc->nursery_fromspace);
82
23
    MVM_free(tc->nursery_tospace);
83
23
    MVM_free(tc->finalizing);
84
23
85
23
    /* Destroy the second generation allocator. */
86
23
    MVM_gc_gen2_destroy(tc->instance, tc->gen2);
87
23
88
23
    /* Destory the per-thread fixed size allocator state. */
89
23
    MVM_fixed_size_destroy_thread(tc);
90
23
91
23
    /* Destroy all callstack regions. */
92
23
    MVM_callstack_region_destroy_all(tc);
93
23
94
23
    /* Free the thread-specific storage */
95
23
    MVM_free(tc->gc_work);
96
23
    MVM_free(tc->temproots);
97
23
    MVM_free(tc->gen2roots);
98
23
    MVM_free(tc->finalize);
99
23
100
23
    /* Free any memory allocated for NFAs and multi-dim indices. */
101
23
    MVM_free(tc->nfa_done);
102
23
    MVM_free(tc->nfa_curst);
103
23
    MVM_free(tc->nfa_nextst);
104
23
    MVM_free(tc->nfa_fates);
105
23
    MVM_free(tc->nfa_longlit);
106
23
    MVM_free(tc->multi_dim_indices);
107
23
108
23
    /* Destroy the libuv event loop */
109
23
    uv_loop_delete(tc->loop);
110
23
111
23
    /* Free the thread context itself. */
112
23
    memset(tc, 0, sizeof(MVMThreadContext));
113
23
    MVM_free(tc);
114
23
}
115
116
/* Setting and clearing mutex to release on exception throw. */
117
15.6k
void MVM_tc_set_ex_release_mutex(MVMThreadContext *tc, uv_mutex_t *mutex) {
118
15.6k
    if (tc->ex_release_mutex)
119
0
        MVM_exception_throw_adhoc(tc, "Internal error: multiple ex_release_mutex");
120
15.6k
    tc->ex_release_mutex = mutex;
121
15.6k
}
122
164
void MVM_tc_release_ex_release_mutex(MVMThreadContext *tc) {
123
164
    if (tc->ex_release_mutex)
124
2
        uv_mutex_unlock(tc->ex_release_mutex);
125
164
    tc->ex_release_mutex = NULL;
126
164
}
127
15.6k
void MVM_tc_clear_ex_release_mutex(MVMThreadContext *tc) {
128
15.6k
    tc->ex_release_mutex = NULL;
129
15.6k
}