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

ruby-changes:63579

From: Koichi <ko1@a...>
Date: Wed, 11 Nov 2020 15:49:22 +0900 (JST)
Subject: [ruby-changes:63579] 1e8abe5d03 (master): introduce USE_VM_CLOCK for windows.

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

From 1e8abe5d03ae386af82e2c95ef05170cd9791889 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Wed, 11 Nov 2020 14:37:31 +0900
Subject: introduce USE_VM_CLOCK for windows.

The timer function used on windows system set timer interrupt
flag of current main ractor's executing ec and thread can detect
the end of time slice. However, to set all ec->interrupt_flag for
all running ractors, it is requires to synchronize with other ractors.
However, timer thread can not acquire the ractor-wide lock because
of some limitation.

To solve this issue, this patch introduces USE_VM_CLOCK compile option
to introduce rb_vm_t::clock. This clock will be incremented by the
timer thread and each thread can check the incrementing by comparison
with previous checked clock. At last, on windows platform this patch
introduces some overhead, but I think there is no critical performance
issue because of this modification.

diff --git a/thread.c b/thread.c
index 77cc7e3..d0187ae 100644
--- a/thread.c
+++ b/thread.c
@@ -341,7 +341,6 @@ rb_thread_s_debug_set(VALUE self, VALUE val) https://github.com/ruby/ruby/blob/trunk/thread.c#L341
 #endif
 
 NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start));
-static void timer_thread_function(rb_execution_context_t *ec);
 void ruby_sigchld_handler(rb_vm_t *); /* signal.c */
 
 static void
@@ -4575,15 +4574,6 @@ rb_threadptr_check_signal(rb_thread_t *mth) https://github.com/ruby/ruby/blob/trunk/thread.c#L4574
 }
 
 static void
-timer_thread_function(rb_execution_context_t *ec)
-{
-    // strictly speaking, accessing gvl->owner is not thread-safe
-    if (ec) {
-        RUBY_VM_SET_TIMER_INTERRUPT(ec);
-    }
-}
-
-static void
 async_bug_fd(const char *mesg, int errno_arg, int fd)
 {
     char buff[64];
diff --git a/thread_pthread.c b/thread_pthread.c
index 71667ae..97879f5 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -194,6 +194,7 @@ designate_timer_thread(rb_global_vm_lock_t *gvl) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L194
 static void
 do_gvl_timer(rb_global_vm_lock_t *gvl, rb_thread_t *th)
 {
+    rb_vm_t *vm = GET_VM();
     static rb_hrtime_t abs;
     native_thread_data_t *nd = &th->native_thread_data;
 
@@ -208,14 +209,14 @@ do_gvl_timer(rb_global_vm_lock_t *gvl, rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L209
     gvl->timer_err = native_cond_timedwait(&nd->cond.gvlq, &gvl->lock, &abs);
 
     ubf_wakeup_all_threads();
-    ruby_sigchld_handler(GET_VM());
+    ruby_sigchld_handler(vm);
 
     if (UNLIKELY(rb_signal_buff_size())) {
-        if (th == GET_VM()->ractor.main_thread) {
+        if (th == vm->ractor.main_thread) {
             RUBY_VM_SET_TRAP_INTERRUPT(th->ec);
         }
         else {
-            threadptr_trap_interrupt(GET_VM()->ractor.main_thread);
+            threadptr_trap_interrupt(vm->ractor.main_thread);
         }
     }
 
@@ -223,7 +224,10 @@ do_gvl_timer(rb_global_vm_lock_t *gvl, rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L224
      * Timeslice.  Warning: the process may fork while this
      * thread is contending for GVL:
      */
-    if (gvl->owner) timer_thread_function(gvl->owner->ec);
+    if (gvl->owner) {
+        // strictly speaking, accessing "gvl->owner" is not thread-safe
+        RUBY_VM_SET_TIMER_INTERRUPT(gvl->owner->ec);
+    }
     gvl->timer = 0;
 }
 
diff --git a/thread_win32.c b/thread_win32.c
index 9b80bfc..132e52c 100644
--- a/thread_win32.c
+++ b/thread_win32.c
@@ -710,13 +710,9 @@ timer_thread_func(void *dummy) https://github.com/ruby/ruby/blob/trunk/thread_win32.c#L710
     rb_vm_t *vm = GET_VM();
     thread_debug("timer_thread\n");
     rb_w32_set_thread_description(GetCurrentThread(), L"ruby-timer-thread");
-    while (WaitForSingleObject(timer_thread.lock, TIME_QUANTUM_USEC/1000) ==
-	   WAIT_TIMEOUT) {
-        rb_execution_context_t *running_ec = vm->ractor.main_ractor->threads.running_ec;
-
-        if (running_ec) {
-            timer_thread_function(running_ec);
-        }
+    while (WaitForSingleObject(timer_thread.lock,
+                               TIME_QUANTUM_USEC/1000) == WAIT_TIMEOUT) {
+        vm->clock++;
 	ruby_sigchld_handler(vm); /* probably no-op */
 	rb_threadptr_check_signal(vm->ractor.main_thread);
     }
diff --git a/thread_win32.h b/thread_win32.h
index cdcc159..bc8eea7 100644
--- a/thread_win32.h
+++ b/thread_win32.h
@@ -16,6 +16,8 @@ https://github.com/ruby/ruby/blob/trunk/thread_win32.h#L16
 # undef _WIN32
 # endif
 
+#define USE_VM_CLOCK 1
+
 WINBASEAPI BOOL WINAPI
 TryEnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection);
 
diff --git a/vm_core.h b/vm_core.h
index 9ef3af5..53bf67c 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -649,6 +649,10 @@ typedef struct rb_vm_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L649
     const struct rb_builtin_function *builtin_function_table;
     int builtin_inline_index;
 
+#if USE_VM_CLOCK
+    uint32_t clock;
+#endif
+
     /* params */
     struct { /* size in byte */
 	size_t thread_vm_stack_size;
@@ -845,6 +849,9 @@ struct rb_execution_context_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L849
     /* interrupt flags */
     rb_atomic_t interrupt_flag;
     rb_atomic_t interrupt_mask; /* size should match flag */
+#if USE_VM_CLOCK
+    uint32_t checked_clock;
+#endif
 
     rb_fiber_t *fiber_ptr;
     struct rb_thread_struct *thread_ptr;
@@ -1845,7 +1852,20 @@ enum { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1852
 #define RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec)    ATOMIC_OR((ec)->interrupt_flag, VM_BARRIER_INTERRUPT_MASK)
 #define RUBY_VM_INTERRUPTED(ec)			((ec)->interrupt_flag & ~(ec)->interrupt_mask & \
 						 (PENDING_INTERRUPT_MASK|TRAP_INTERRUPT_MASK))
-#define RUBY_VM_INTERRUPTED_ANY(ec)		((ec)->interrupt_flag & ~(ec)->interrupt_mask)
+
+static inline bool
+RUBY_VM_INTERRUPTED_ANY(rb_execution_context_t *ec)
+{
+#if USE_VM_CLOCK
+    uint32_t current_clock = rb_ec_vm_ptr(ec)->clock;
+
+    if (current_clock != ec->checked_clock) {
+        ec->checked_clock = current_clock;
+        RUBY_VM_SET_TIMER_INTERRUPT(ec);
+    }
+#endif
+    return ec->interrupt_flag & ~(ec)->interrupt_mask;
+}
 
 VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt);
 int rb_signal_buff_size(void);
-- 
cgit v0.10.2


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

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