Kim Jørgensen
64 posts
GetThreadID on Linux and Mac?
I was wondering if it is possible to implement a lightweight version of GetThreadID that works on both Linux and Mac.

The following implementation is based on the disassembly of pthread_self and works on my machine™.

 1 2 3 4 5 6 inline u32 GetThreadID(void) { u32 ThreadID; asm ("mov %%fs:0x10,%0" : "=r" (ThreadID)); return ThreadID; } 

Does anybody know how portable this code is, will it work on Mac OS X?

Oh, and please point out if I did something stupid. I obviously have no clue what I am doing.

/Kim
Mārtiņš Možeiko
2262 posts / 2 projects
GetThreadID on Linux and Mac?
Edited by Mārtiņš Možeiko on
Source for pthread_self for Linux can be found here: https://sourceware.org/git/?p=gli...f=nptl/pthread_self.c;hb=HEAD#l26
 1 2 3 4 5 pthread_t __pthread_self (void) { return (pthread_t) THREAD_SELF; } 

THREAD_SELF is architecture specific.

For 32-bit Intel it is https://sourceware.org/git/?p=gli...deps/i386/nptl/tls.h;hb=HEAD#l251
 1 2 3 4 5 # define THREAD_SELF \ ({ struct pthread *__self; \ asm ("movl %%gs:%c1,%0" : "=r" (__self) \ : "i" (offsetof (struct pthread, header.self))); \ __self;}) 

For 64-bit Intel it is https://sourceware.org/git/?p=gli...ps/x86_64/nptl/tls.h;hb=HEAD#l183
 1 2 3 4 5 # define THREAD_SELF \ ({ struct pthread *__self; \ asm ("mov %%fs:%c1,%0" : "=r" (__self) \ : "i" (offsetof (struct pthread, header.self))); \ __self;}) 

header.self is a member of struct pthread https://sourceware.org/git/?p=gli...=blob;f=nptl/descr.h;hb=HEAD#l131
  1 2 3 4 5 6 7 8 9 10 11 struct pthread { union { #if !TLS_DTV_AT_TP /* This overlaps the TCB as used for TLS without threads (see tls.h). */ tcbhead_t header; #else struct { ... 

And tcbhead_t is architecture dependent.

For 32-bit Intel arch https://sourceware.org/git/?p=gli...sdeps/i386/nptl/tls.h;hb=HEAD#l45
 1 2 3 4 5 6 7 8 typedef struct { void *tcb; /* Pointer to the TCB. Not necessarily the thread descriptor used by libpthread. */ dtv_t *dtv; void *self; /* Pointer to the thread descriptor. */ ... } tcbhead_t; 

For 64-bit Intel arch https://sourceware.org/git/?p=gli...eps/x86_64/nptl/tls.h;hb=HEAD#l53
 1 2 3 4 5 6 7 8 typedef struct { void *tcb; /* Pointer to the TCB. Not necessarily the thread descriptor used by libpthread. */ dtv_t *dtv; void *self; /* Pointer to the thread descriptor. */ ... } tcbhead_t; 

That means this should work for both 32-bit and 64-bit Intel architecture:
  1 2 3 4 5 6 7 8 9 10 11 12 inline u32 GetThreadID(void) { void *ThreadID; #if defined(__i386__) asm("movl %%gs:0x08,%0" : "=r"(ThreadID)); #elif defined(__x86_64__) asm("mov %%fs:0x10,%0" : "=r"(ThreadID)); #else #error Unsupported architecture #endif return (u32)ThreadID; } 

You can easily add other architectures by looking in individual sysdeps/ARCH/ntpl/tls.h headers.
Kim Jørgensen
64 posts
GetThreadID on Linux and Mac?
Thank you for your research. Though I am not sure I find it that easy :)