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
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.

Edited by Mārtiņš Možeiko on
Thank you for your research. Though I am not sure I find it that easy :)