Free stack memory at end of fiber

Immediately frees the call stack and data stack at the end of a non-root fiber.
If the env object needs to be detached, the data stack is reused through `mrb_realloc()`.

Previously, it was not necessary to take into account that `c->cibase` could be `NULL`.
Note that this is no longer the case due to this patch.
In fact, changes to "mruby-fiber" are now required.
This commit is contained in:
dearblue
2024-04-09 21:13:32 +09:00
parent 3ce5f3acbc
commit f3b393272c
2 changed files with 42 additions and 3 deletions
+4 -3
View File
@@ -223,7 +223,6 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
return fiber_error(mrb, "attempt to resume the current fiber");
}
fiber_check_cfunc(mrb, c);
status = c->status;
switch (status) {
case MRB_FIBER_TRANSFERRED:
@@ -241,6 +240,7 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
default:
break;
}
fiber_check_cfunc(mrb, c);
if (resume) {
old_c->status = MRB_FIBER_RESUMED;
c->prev = mrb->c;
@@ -394,8 +394,9 @@ fiber_to_s(mrb_state *mrb, mrb_value self)
const char *file;
int32_t line;
const struct RProc *p = f->cxt->cibase->proc;
if (f->cxt->status != MRB_FIBER_TERMINATED && !MRB_PROC_CFUNC_P(p) && !MRB_PROC_ALIAS_P(p) &&
const struct RProc *p;
if (f->cxt->status != MRB_FIBER_TERMINATED &&
!MRB_PROC_CFUNC_P(p = f->cxt->cibase->proc) && !MRB_PROC_ALIAS_P(p) &&
mrb_debug_get_position(mrb, p->body.irep, 0, &line, &file)) {
mrb_str_cat_lit(mrb, s, " ");
mrb_str_cat_cstr(mrb, s, file);
+38
View File
@@ -374,7 +374,45 @@ fiber_terminate(mrb_state *mrb, struct mrb_context *c, mrb_callinfo *ci)
{
mrb_assert(c != mrb->root_c);
struct REnv *env = CI_ENV(ci);
mrb_assert(env == NULL || MRB_ENV_LEN(env) <= c->stend - ci->stack);
c->status = MRB_FIBER_TERMINATED;
mrb_free(mrb, c->cibase);
c->cibase = c->ciend = c->ci = NULL;
mrb_value *stack = c->stbase;
c->stbase = c->stend = NULL;
if (!env) {
mrb_free(mrb, stack);
}
else {
env->cxt = NULL;
size_t len = (size_t)MRB_ENV_LEN(env);
if (len == 0) {
env->stack = NULL;
MRB_ENV_CLOSE(env);
mrb_free(mrb, stack);
}
else {
mrb_assert(stack == env->stack);
mrb_write_barrier(mrb, (struct RBasic*)env);
// don't call MRB_ENV_CLOSE() before mrb_realloc().
// the reason is that env->stack may be freed by mrb_realloc() if MRB_DEBUG + MRB_GC_STRESS are enabled.
// realloc() on a freed heap will cause double-free.
stack = (mrb_value*)mrb_realloc(mrb, stack, len * sizeof(mrb_value));
if (mrb_object_dead_p(mrb, (struct RBasic*)env)) {
mrb_free(mrb, stack);
}
else {
env->stack = stack;
MRB_ENV_CLOSE(env);
}
}
}
/* fiber termination should automatic yield or transfer to root */
mrb->c = c->prev;