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

ruby-changes:51672

From: normal <ko1@a...>
Date: Sun, 8 Jul 2018 16:27:29 +0900 (JST)
Subject: [ruby-changes:51672] normal:r63884 (trunk): mjit: get rid of memory leak in pause+resume loop

normal	2018-07-08 16:27:24 +0900 (Sun, 08 Jul 2018)

  New Revision: 63884

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63884

  Log:
    mjit: get rid of memory leak in pause+resume loop
    
    pthread_atfork is not idempotent and repeatedly calling it
    causes it to register the same hook repeatedly; leading to
    unbound memory growth.
    
    Ruby already has a (confusing-named) internal API for to call
    in the forked child process: rb_thread_atfork
    Call the MJIT child_after_fork hook inside that to prevent
    unbound growth with the following loop:
    
        loop do
          RubyVM::MJIT.pause
          RubyVM::MJIT.resume
        end

  Modified files:
    trunk/mjit.c
    trunk/thread.c
    trunk/thread_pthread.c
    trunk/thread_win32.c
Index: thread_win32.c
===================================================================
--- thread_win32.c	(revision 63883)
+++ thread_win32.c	(revision 63884)
@@ -790,7 +790,7 @@ mjit_worker(void *arg) https://github.com/ruby/ruby/blob/trunk/thread_win32.c#L790
 
 /* Launch MJIT thread. Returns FALSE if it fails to create thread. */
 int
-rb_thread_create_mjit_thread(void (*child_hook)(void), void (*worker_func)(void))
+rb_thread_create_mjit_thread(void (*worker_func)(void))
 {
     size_t stack_size = 4 * 1024; /* 4KB is the minimum commit size */
     HANDLE thread_id = w32_create_thread(stack_size, mjit_worker, worker_func);
Index: thread_pthread.c
===================================================================
--- thread_pthread.c	(revision 63883)
+++ thread_pthread.c	(revision 63884)
@@ -1767,14 +1767,12 @@ mjit_worker(void *arg) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L1767
 
 /* Launch MJIT thread. Returns FALSE if it fails to create thread. */
 int
-rb_thread_create_mjit_thread(void (*child_hook)(void), void (*worker_func)(void))
+rb_thread_create_mjit_thread(void (*worker_func)(void))
 {
     pthread_attr_t attr;
     pthread_t worker_pid;
     int ret = FALSE;
 
-    pthread_atfork(NULL, NULL, child_hook);
-
     if (pthread_attr_init(&attr) != 0) return ret;
 
     /* jit_worker thread is not to be joined */
Index: thread.c
===================================================================
--- thread.c	(revision 63883)
+++ thread.c	(revision 63884)
@@ -4276,6 +4276,8 @@ terminate_atfork_i(rb_thread_t *th, cons https://github.com/ruby/ruby/blob/trunk/thread.c#L4276
     }
 }
 
+/* mjit.c */
+void mjit_child_after_fork(void);
 void
 rb_thread_atfork(void)
 {
@@ -4286,6 +4288,7 @@ rb_thread_atfork(void) https://github.com/ruby/ruby/blob/trunk/thread.c#L4288
 
     /* We don't want reproduce CVE-2003-0900. */
     rb_reset_random_seed();
+    mjit_child_after_fork();
 }
 
 static void
Index: mjit.c
===================================================================
--- mjit.c	(revision 63883)
+++ mjit.c	(revision 63884)
@@ -117,7 +117,7 @@ extern void rb_native_cond_signal(rb_nat https://github.com/ruby/ruby/blob/trunk/mjit.c#L117
 extern void rb_native_cond_broadcast(rb_nativethread_cond_t *cond);
 extern void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex);
 
-extern int rb_thread_create_mjit_thread(void (*child_hook)(void), void (*worker_func)(void));
+extern int rb_thread_create_mjit_thread(void (*worker_func)(void));
 
 /* process.c */
 rb_pid_t ruby_waitpid_locked(rb_vm_t *, rb_pid_t, int *status, int options,
@@ -1319,11 +1319,13 @@ init_header_filename(void) https://github.com/ruby/ruby/blob/trunk/mjit.c#L1319
 
 /* This is called after each fork in the child in to switch off MJIT
    engine in the child as it does not inherit MJIT threads.  */
-static void
-child_after_fork(void)
+void
+mjit_child_after_fork(void)
 {
-    verbose(3, "Switching off MJIT in a forked child");
-    mjit_enabled = FALSE;
+    if (mjit_enabled) {
+        verbose(3, "Switching off MJIT in a forked child");
+        mjit_enabled = FALSE;
+    }
     /* TODO: Should we initiate MJIT in the forked Ruby.  */
 }
 
@@ -1433,7 +1435,7 @@ start_worker(void) https://github.com/ruby/ruby/blob/trunk/mjit.c#L1435
     stop_worker_p = FALSE;
     worker_stopped = FALSE;
 
-    if (!rb_thread_create_mjit_thread(child_after_fork, worker)) {
+    if (!rb_thread_create_mjit_thread(worker)) {
         mjit_enabled = FALSE;
         rb_native_mutex_destroy(&mjit_engine_mutex);
         rb_native_cond_destroy(&mjit_pch_wakeup);

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

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