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