[前][次][番号順一覧][スレッド一覧]

ruby-changes:63683

From: Takashi <ko1@a...>
Date: Sun, 22 Nov 2020 12:37:19 +0900 (JST)
Subject: [ruby-changes:63683] e0156bd396 (master): Make sure all threads are scanned on unload_units

https://git.ruby-lang.org/ruby.git/commit/?id=e0156bd396

From e0156bd39656e26971e4236747e9cd4f45f8b35f Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Sat, 21 Nov 2020 19:24:59 -0800
Subject: Make sure all threads are scanned on unload_units

This has been a TODO since 79df14c04b. While adcf0316d1 covered the
root_fiber of the initial thread, it didn't cover root_fibers of other
threads. Now it's hooked properly in rb_threadptr_root_fiber_setup.

With regards to "XXX: Is this mjit_cont `mjit_cont_free`d?", when
rb_threadptr_root_fiber_release is called, although I'm not sure when
th->root_fiber is truthy, fiber_free seems to call cont_free and
mjit_cont_free. So mjit_conts of root_fibers seem to be freed properly.

diff --git a/cont.c b/cont.c
index 6c26885..9b2ad58 100644
--- a/cont.c
+++ b/cont.c
@@ -945,7 +945,8 @@ cont_free(void *ptr) https://github.com/ruby/ruby/blob/trunk/cont.c#L945
 
     RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
 
-    if (mjit_enabled && cont->mjit_cont != NULL) {
+    if (mjit_enabled) {
+        VM_ASSERT(cont->mjit_cont != NULL);
         mjit_cont_free(cont->mjit_cont);
     }
     /* free rb_cont_t or rb_fiber_t */
@@ -1155,11 +1156,10 @@ VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber) https://github.com/ruby/ruby/blob/trunk/cont.c#L1156
     return fiber->cont.self;
 }
 
+// This is used for root_fiber because other fibers call cont_init_mjit_cont through cont_new.
 void
 rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber)
 {
-    // Currently this function is meant for root_fiber. Others go through cont_new.
-    // XXX: Is this mjit_cont `mjit_cont_free`d?
     cont_init_mjit_cont(&fiber->cont);
 }
 
@@ -1987,6 +1987,9 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/cont.c#L1987
     fiber->blocking = 1;
     fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
     th->ec = &fiber->cont.saved_ec;
+    // This skips mjit_cont_new for the initial thread because mjit_enabled is always false
+    // at this point. mjit_init calls rb_fiber_init_mjit_cont again for this root_fiber.
+    rb_fiber_init_mjit_cont(fiber);
 }
 
 void
diff --git a/mjit.c b/mjit.c
index cc6e3da..f6c402d 100644
--- a/mjit.c
+++ b/mjit.c
@@ -262,7 +262,7 @@ mark_ec_units(rb_execution_context_t *ec) https://github.com/ruby/ruby/blob/trunk/mjit.c#L262
         if (cfp->pc && (iseq = cfp->iseq) != NULL
             && imemo_type((VALUE) iseq) == imemo_iseq
             && (iseq->body->jit_unit) != NULL) {
-            iseq->body->jit_unit->used_code_p = TRUE;
+            iseq->body->jit_unit->used_code_p = true;
         }
 
         if (cfp == ec->cfp)
@@ -275,8 +275,6 @@ mark_ec_units(rb_execution_context_t *ec) https://github.com/ruby/ruby/blob/trunk/mjit.c#L275
 static void
 unload_units(void)
 {
-    //rb_vm_t *vm = GET_THREAD()->vm;
-    //rb_thread_t *th = NULL;
     struct rb_mjit_unit *unit = 0, *next, *worst;
     struct mjit_cont *cont;
     int delete_num, units_num = active_units.length;
@@ -293,16 +291,14 @@ unload_units(void) https://github.com/ruby/ruby/blob/trunk/mjit.c#L291
     // Detect units which are in use and can't be unloaded.
     list_for_each(&active_units.head, unit, unode) {
         assert(unit->iseq != NULL && unit->handle != NULL);
-        unit->used_code_p = FALSE;
+        unit->used_code_p = false;
     }
-    // TODO
-    //list_for_each(&vm->living_threads, th, lt_node) {
-    //    mark_ec_units(th->ec);
-    //}
+    // All threads have a root_fiber which has a mjit_cont. Other normal fibers also
+    // have a mjit_cont. Thus we can check ISeqs in use by scanning ec of mjit_conts.
     for (cont = first_cont; cont != NULL; cont = cont->next) {
         mark_ec_units(cont->ec);
     }
-    // TODO: check slale_units and unload unused ones! (note that the unit is not associated to ISeq anymore)
+    // TODO: check stale_units and unload unused ones! (note that the unit is not associated to ISeq anymore)
 
     // Remove 1/10 units more to decrease unloading calls.
     // TODO: Calculate max total_calls in unit_queue and don't unload units
@@ -801,7 +797,11 @@ mjit_init(const struct mjit_options *opts) https://github.com/ruby/ruby/blob/trunk/mjit.c#L797
     rb_native_cond_initialize(&mjit_worker_wakeup);
     rb_native_cond_initialize(&mjit_gc_wakeup);
 
-    // Make sure root_fiber's saved_ec is scanned by mark_ec_units
+    // Make sure the saved_ec of the initial thread's root_fiber is scanned by mark_ec_units.
+    //
+    // rb_threadptr_root_fiber_setup for the initial thread is called before mjit_init,
+    // meaning mjit_cont_new is skipped for the root_fiber. Therefore we need to call
+    // rb_fiber_init_mjit_cont again with mjit_enabled=true to set the root_fiber's mjit_cont.
     rb_fiber_init_mjit_cont(GET_EC()->fiber_ptr);
 
     // Initialize class_serials cache for compilation
diff --git a/mjit_worker.c b/mjit_worker.c
index d410117..c024085 100644
--- a/mjit_worker.c
+++ b/mjit_worker.c
@@ -166,7 +166,7 @@ struct rb_mjit_unit { https://github.com/ruby/ruby/blob/trunk/mjit_worker.c#L166
     char *so_file;
 #endif
     // Only used by unload_units. Flag to check this unit is currently on stack or not.
-    char used_code_p;
+    bool used_code_p;
     struct list_node unode;
     // mjit_compile's optimization switches
     struct rb_mjit_compile_info compile_info;
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]