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