Skip to content

Commit 4665515

Browse files
committed
Add Thread#native_thread_id [Feature #17853]
1 parent 88e3848 commit 4665515

File tree

5 files changed

+104
-0
lines changed

5 files changed

+104
-0
lines changed

test/ruby/test_thread.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,27 @@ def test_thread_setname_in_initialize
13341334
assert_equal("foo", c.new {Thread.current.name}.value, bug12290)
13351335
end
13361336

1337+
def test_thread_native_thread_id
1338+
skip "don't support native_thread_id" unless (Thread.main.native_thread_id rescue nil)
1339+
assert_instance_of Integer, Thread.main.native_thread_id
1340+
1341+
th1 = Thread.start{sleep}
1342+
1343+
# newly created thread which doesn't run yet returns nil or integer
1344+
assert_include [NilClass, Integer], th1.native_thread_id.class
1345+
1346+
Thread.pass until th1.stop?
1347+
1348+
# After a thread starts (and execute `sleep`), it returns native_thread_id
1349+
assert_instance_of Integer, th1.native_thread_id
1350+
1351+
th1.wakeup
1352+
Thread.pass while th1.alive?
1353+
1354+
# dead thread returns nil
1355+
assert_nil th1.native_thread_id
1356+
end
1357+
13371358
def test_thread_interrupt_for_killed_thread
13381359
opts = { timeout: 5, timeout_error: nil }
13391360

thread.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,36 @@ rb_thread_setname(VALUE thread, VALUE name)
34023402
return name;
34033403
}
34043404

3405+
/*
3406+
* call-seq:
3407+
* thr.native_thread_id -> integer
3408+
*
3409+
* Return the native thread ID which is used by the Ruby thread.
3410+
*
3411+
* The ID depends on the OS. (not POSIX thread ID returned by pthread_self(3))
3412+
* * On Linux it is TID returned by gettid(2).
3413+
* * On macOS it is the system-wide unique integral ID of thread returned
3414+
* by pthread_threadid_np(3).
3415+
* * On FreeBSD it is the unique integral ID of the thread returned by
3416+
* pthread_getthreadid_np(3).
3417+
* * On Windows it is the thread identifier returned by GetThreadId().
3418+
* * On other platforms, it raises NotImplementedError.
3419+
*
3420+
* NOTE:
3421+
* If the thread is not associated yet or already deassociated with a native
3422+
* thread, it returns _nil_.
3423+
* If the Ruby implementation uses M:N thread model, the ID may change
3424+
* depending on the timing.
3425+
*/
3426+
3427+
static VALUE
3428+
rb_thread_native_thread_id(VALUE thread)
3429+
{
3430+
rb_thread_t *target_th = rb_thread_ptr(thread);
3431+
if (rb_threadptr_dead(target_th)) return Qnil;
3432+
return native_thread_native_thread_id(target_th);
3433+
}
3434+
34053435
/*
34063436
* call-seq:
34073437
* thr.to_s -> string
@@ -5494,6 +5524,7 @@ Init_Thread(void)
54945524

54955525
rb_define_method(rb_cThread, "name", rb_thread_getname, 0);
54965526
rb_define_method(rb_cThread, "name=", rb_thread_setname, 1);
5527+
rb_define_method(rb_cThread, "native_thread_id", rb_thread_native_thread_id, 0);
54975528
rb_define_method(rb_cThread, "to_s", rb_thread_to_s, 0);
54985529
rb_define_alias(rb_cThread, "inspect", "to_s");
54995530

thread_pthread.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
#if defined(__HAIKU__)
3535
#include <kernel/OS.h>
3636
#endif
37+
#ifdef __linux__
38+
#include <sys/syscall.h> /* for SYS_gettid */
39+
#endif
3740
#include <time.h>
3841
#include <signal.h>
3942

@@ -659,11 +662,26 @@ Init_native_thread(rb_thread_t *th)
659662
posix_signal(SIGVTALRM, null_func);
660663
}
661664

665+
#ifdef RB_THREAD_T_HAS_NATIVE_ID
666+
static int
667+
get_native_thread_id(void)
668+
{
669+
#ifdef __linux__
670+
return (int)syscall(SYS_gettid);
671+
#elif defined(__FreeBSD__)
672+
return pthread_getthreadid_np();
673+
#endif
674+
}
675+
#endif
676+
662677
static void
663678
native_thread_init(rb_thread_t *th)
664679
{
665680
native_thread_data_t *nd = &th->native_thread_data;
666681

682+
#ifdef RB_THREAD_T_HAS_NATIVE_ID
683+
th->tid = get_native_thread_id();
684+
#endif
667685
#ifdef USE_UBF_LIST
668686
list_node_init(&nd->node.ubf);
669687
#endif
@@ -1708,6 +1726,25 @@ native_set_another_thread_name(rb_nativethread_id_t thread_id, VALUE name)
17081726
#endif
17091727
}
17101728

1729+
static VALUE
1730+
native_thread_native_thread_id(rb_thread_t *target_th)
1731+
{
1732+
#if !defined(RB_THREAD_T_HAS_NATIVE_ID) && !defined(__APPLE__)
1733+
rb_notimplement();
1734+
#endif
1735+
1736+
#ifdef RB_THREAD_T_HAS_NATIVE_ID
1737+
int tid = target_th->tid;
1738+
if (tid == 0) return Qnil;
1739+
return INT2FIX(tid);
1740+
#elif defined(__APPLE__)
1741+
uint64_t tid;
1742+
int e = pthread_threadid_np(target_th->thread_id, &tid);
1743+
if (e != 0) rb_syserr_fail(e, "pthread_threadid_np");
1744+
return ULL2NUM((unsigned long long)tid);
1745+
#endif
1746+
}
1747+
17111748
static void
17121749
ubf_timer_invalidate(void)
17131750
{

thread_win32.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,14 @@ native_set_thread_name(rb_thread_t *th)
835835
{
836836
}
837837

838+
static VALUE
839+
native_thread_native_thread_id(rb_thread_t *th)
840+
{
841+
DWORD tid = GetThreadId(th->thread_id);
842+
if (tid == 0) rb_sys_fail("GetThreadId");
843+
return ULONG2NUM(tid);
844+
}
845+
838846
#if USE_MJIT
839847
static unsigned long __stdcall
840848
mjit_worker(void *arg)

vm_core.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,10 @@ struct rb_ext_config {
942942

943943
typedef struct rb_ractor_struct rb_ractor_t;
944944

945+
#if defined(__linux__) || defined(__FreeBSD__)
946+
# define RB_THREAD_T_HAS_NATIVE_ID
947+
#endif
948+
945949
typedef struct rb_thread_struct {
946950
struct list_node lt_node; // managed by a ractor
947951
VALUE self;
@@ -963,6 +967,9 @@ typedef struct rb_thread_struct {
963967
rb_nativethread_id_t thread_id;
964968
#ifdef NON_SCALAR_THREAD_ID
965969
rb_thread_id_string_t thread_id_string;
970+
#endif
971+
#ifdef RB_THREAD_T_HAS_NATIVE_ID
972+
int tid;
966973
#endif
967974
BITFIELD(enum rb_thread_status, status, 2);
968975
/* bit flags */

0 commit comments

Comments
 (0)