summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKJ Tsanaktsidis <[email protected]>2023-09-15 11:33:32 +1000
committerGitHub <[email protected]>2023-09-15 10:33:32 +0900
commit0117a6d389c5b607eaec1b7f917132efa356f665 (patch)
tree573381ae40e12579515be9e571aef2590f89c76f
parentf08cac066e3d327f2925607d7a33c8e9738aa4ee (diff)
Fix Thread#native_thread_id being cached across fork (#8418)
The native thread ID can and does change on some operating systems (e.g. Linux) after forking, so it needs to be re-queried. [Bug #19873]
Notes
Notes: Merged-By: nurse <[email protected]>
-rw-r--r--test/ruby/test_thread.rb30
-rw-r--r--thread_pthread.c27
2 files changed, 45 insertions, 12 deletions
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index 703373b11e..bcd6590903 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -3,6 +3,7 @@
require 'test/unit'
require "rbconfig/sizeof"
require "timeout"
+require "fiddle"
class TestThread < Test::Unit::TestCase
class Thread < ::Thread
@@ -1443,6 +1444,35 @@ q.pop
assert_nil th1.native_thread_id
end
+ def test_thread_native_thread_id_across_fork_on_linux
+ rtld_default = Fiddle.dlopen(nil)
+ omit "this test is only for Linux" unless rtld_default.sym_defined?('gettid')
+
+ gettid = Fiddle::Function.new(rtld_default['gettid'], [], Fiddle::TYPE_INT)
+
+ parent_thread_id = Thread.main.native_thread_id
+ real_parent_thread_id = gettid.call
+
+ assert_equal real_parent_thread_id, parent_thread_id
+
+ child_lines = nil
+ IO.popen('-') do |pipe|
+ if pipe
+ # parent
+ child_lines = pipe.read.lines
+ else
+ # child
+ puts Thread.main.native_thread_id
+ puts gettid.call
+ end
+ end
+ child_thread_id = child_lines[0].chomp.to_i
+ real_child_thread_id = child_lines[1].chomp.to_i
+
+ assert_equal real_child_thread_id, child_thread_id
+ refute_equal parent_thread_id, child_thread_id
+ end
+
def test_thread_interrupt_for_killed_thread
opts = { timeout: 5, timeout_error: nil }
diff --git a/thread_pthread.c b/thread_pthread.c
index 057c50c124..7c53325240 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -637,6 +637,18 @@ rb_thread_sched_destroy(struct rb_thread_sched *sched)
clear_thread_cache_altstack();
}
+#ifdef RB_THREAD_T_HAS_NATIVE_ID
+static int
+get_native_thread_id(void)
+{
+#ifdef __linux__
+ return (int)syscall(SYS_gettid);
+#elif defined(__FreeBSD__)
+ return pthread_getthreadid_np();
+#endif
+}
+#endif
+
#if defined(HAVE_WORKING_FORK)
static void thread_cache_reset(void);
static void
@@ -646,6 +658,9 @@ thread_sched_atfork(struct rb_thread_sched *sched)
thread_cache_reset();
rb_thread_sched_init(sched);
thread_sched_to_running(sched, GET_THREAD());
+#ifdef RB_THREAD_T_HAS_NATIVE_ID
+ GET_THREAD()->nt->tid = get_native_thread_id();
+#endif
}
#endif
@@ -693,18 +708,6 @@ ruby_thread_set_native(rb_thread_t *th)
#endif
}
-#ifdef RB_THREAD_T_HAS_NATIVE_ID
-static int
-get_native_thread_id(void)
-{
-#ifdef __linux__
- return (int)syscall(SYS_gettid);
-#elif defined(__FreeBSD__)
- return pthread_getthreadid_np();
-#endif
-}
-#endif
-
static void
native_thread_init(struct rb_native_thread *nt)
{