/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 | } |