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]
This commit is contained in:
KJ Tsanaktsidis 2023-09-15 11:33:32 +10:00 committed by GitHub
parent f08cac066e
commit 0117a6d389
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2023-09-15 01:33:51 +00:00
Merged-By: nurse <naruse@airemix.jp>
2 changed files with 45 additions and 12 deletions

View File

@ -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 }

View File

@ -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)
{