Change soft-fail to use the config, rather than env
[rbx.git] / shotgun / lib / state.c
blob30456d223b56b497ac63a72ebeee618b28bc3a6b
1 #include <stdlib.h>
2 #include <string.h>
3 #include <sys/time.h>
5 #include "shotgun/lib/shotgun.h"
6 #include "shotgun/lib/cpu.h"
7 #include "shotgun/lib/cleanup_hash.h"
8 #include "shotgun/lib/config_hash.h"
9 #include "shotgun/lib/machine.h"
11 #ifdef TIME_LOOKUP
12 #include <mach/mach_time.h>
13 #endif
15 static size_t _gc_current_limit = 0;
16 #define GC_EXTERNAL_LIMIT 10000000
18 static void inc_mem(size_t n) {
19 _gc_current_limit += n;
21 if(_gc_current_limit > GC_EXTERNAL_LIMIT) {
22 _gc_current_limit = 0;
23 current_machine->s->om->collect_now = OMCollectYoung;
27 void *XMALLOC(size_t n) {
28 inc_mem(n);
29 return malloc(n);
32 void *XREALLOC(void *p, size_t n) {
33 inc_mem(n);
34 return realloc(p, n);
37 void *XCALLOC(size_t n, size_t s) {
38 inc_mem(n * s);
39 return calloc(n, s);
42 void XFREE(void *p) {
43 free(p);
46 rstate rubinius_state_new() {
47 rstate st;
48 st = (rstate)calloc(1, sizeof(struct rubinius_state));
49 st->om = object_memory_new();
50 st->global = (struct rubinius_globals*)calloc(1, sizeof(struct rubinius_globals));
51 st->cleanup = ht_cleanup_create(11);
52 st->config = ht_config_create(11);
53 #ifdef TIME_LOOKUP
54 st->system_start = mach_absolute_time();
55 st->lookup_time = 0;
56 #endif
57 return st;
60 void state_destroy(STATE) {
61 object_memory_destroy(state->om);
62 free(state->global);
64 ht_cleanup_destroy(state->cleanup);
65 ht_config_destroy(state->config);
67 free(state);
70 static ptr_array _gather_roots(STATE, cpu c) {
71 ptr_array roots;
72 roots = ptr_array_new(NUM_OF_GLOBALS + 100);
74 memcpy(roots->array, state->global, sizeof(struct rubinius_globals));
75 roots->length = NUM_OF_GLOBALS;
77 cpu_add_roots(state, c, roots);
78 /* truncate the free_context list since we don't care about them
79 after we've collected anyway */
80 return roots;
83 void cpu_sampler_suspend(STATE);
84 void cpu_sampler_resume(STATE);
85 void cpu_hard_cache(STATE, cpu c);
87 void state_collect(STATE, cpu c) {
88 ptr_array roots;
89 int stats = state->gc_stats;
90 struct timeval start, fin;
92 state->in_gc = 1;
94 cpu_task_flush(state, c);
96 if(stats) {
97 gettimeofday(&start, NULL);
100 cpu_flush_ip(c);
101 cpu_flush_sp(c);
103 state->current_stack = c->stack_top;
104 state->current_sp = c->sp_ptr;
106 /* HACK: external_ivars needs to be moved out of being a generic
107 global and being a special case one so that it's references
108 can't keep objects alive. */
110 cpu_sampler_suspend(state);
111 object_memory_formalize_contexts(state, state->om);
112 roots = _gather_roots(state, c);
113 object_memory_collect(state, state->om, roots);
114 memcpy(state->global, roots->array, sizeof(struct rubinius_globals));
115 cpu_update_roots(state, c, roots, NUM_OF_GLOBALS);
117 object_memory_reset_contexts(state, state->om);
119 ptr_array_free(roots);
121 baker_gc_find_lost_souls(state, state->om->gc);
122 cpu_sampler_resume(state);
124 if(stats) {
125 double elapse;
126 gettimeofday(&fin, NULL);
127 elapse = (fin.tv_sec - start.tv_sec);
128 elapse += (((double)fin.tv_usec - start.tv_usec) / 1000000);
129 printf("[GC Y %f secs, %ldK total, %3dK used, %4d tenured, %d]\n",
130 elapse,
131 (long int)(state->om->gc->current->size / 1024),
132 (unsigned int)(((uintptr_t)state->om->gc->current->current - (uintptr_t)state->om->gc->current->address) / 1024),
133 state->om->last_tenured,
134 state->om->gc->num_collection
138 cpu_task_flush(state, c);
139 cpu_hard_cache(state, c);
140 cpu_cache_sp(c);
142 state->in_gc = 0;
146 void state_major_collect(STATE, cpu c) {
147 ptr_array roots;
148 int stats = state->gc_stats;
149 struct timeval start, fin;
151 state->in_gc = 1;
152 cpu_task_flush(state, c);
154 state_collect(state, c);
156 if(stats) {
157 gettimeofday(&start, NULL);
160 cpu_flush_ip(c);
161 cpu_flush_sp(c);
163 /* HACK: external_ivars needs to be moved out of being a generic
164 global and being a special case one so that it's references
165 can't keep objects alive. */
167 state->current_stack = c->stack_top;
168 state->current_sp = c->sp_ptr;
170 cpu_sampler_suspend(state);
171 roots = _gather_roots(state, c);
172 object_memory_major_collect(state, state->om, roots);
173 memcpy(state->global, roots->array, sizeof(struct rubinius_globals));
174 cpu_update_roots(state, c, roots, NUM_OF_GLOBALS);
176 ptr_array_free(roots);
177 cpu_sampler_suspend(state);
179 if(stats) {
180 double elapse;
181 gettimeofday(&fin, NULL);
182 elapse = (fin.tv_sec - start.tv_sec);
183 elapse += (((double)fin.tv_usec - start.tv_usec) / 1000000);
185 printf("[GC M %f secs, %d freed, %d total, %d segments, %6dK total]\n",
186 elapse,
187 state->om->ms->last_freed, state->om->ms->last_marked,
188 state->om->ms->num_chunks,
189 state->om->ms->allocated_bytes / 1024
193 cpu_task_flush(state, c);
194 cpu_hard_cache(state, c);
195 cpu_cache_sp(c);
196 state->in_gc = 0;
199 void state_object_become(STATE, cpu c, OBJECT from, OBJECT to) {
200 ptr_array roots;
202 state->current_stack = c->stack_top;
203 state->current_sp = c->sp_ptr;
205 roots = _gather_roots(state, c);
207 object_memory_setup_become(state, state->om, from, to);
209 /* If from is young, then all the refs are from other young objects
210 or the remember set, so we just need to mutate in the young space. */
211 if(from->gc_zone == YoungObjectZone) {
212 object_memory_collect(state, state->om, roots);
213 } else {
214 object_memory_major_collect(state, state->om, roots);
217 object_memory_clear_become(state, state->om);
219 memcpy(state->global, roots->array, sizeof(struct rubinius_globals));
220 cpu_update_roots(state, c, roots, NUM_OF_GLOBALS);
222 ptr_array_free(roots);
226 void state_add_cleanup(STATE, OBJECT cls, state_cleanup_func func) {
227 int type = N2I(class_get_object_type(cls));
229 state->type_info[type].cleanup = func;
230 // printf("Registered cleanup for %p\n", module_get_name(cls));
231 class_set_needs_cleanup(cls, Qtrue);
234 void state_run_cleanup(STATE, OBJECT obj) {
235 state_cleanup_func func;
237 func = state->type_info[obj->obj_type].cleanup;
239 if(func) func(state, obj);
242 void state_setup_type(STATE, int type, struct type_info *info) {
243 state->type_info[type] = *info;