2012-04-04

gettid on Mac OS

The Linux kernel has a gettid(2) call that returns the current thread's thread id. These numbers can be handy. They're useful for debugging/diagnostic purposes, they're useful in conjunction with other tools, and they're using for pulling stuff out of /proc/<pid>/task/<tid>/.

But what about code that needs to run on Mac OS too?

If your program's single-threaded, you can use getpid(3) instead. This might sound silly, but you might well find that limiting your Mac build to a single thread lets you avoid all kinds of Mac OS pthread woe, and lets you get on with more important stuff. But this won't suit everyone.

If you poke around, you'll see that the Darwin/xgnu kernel actually has a gettid(2) system call. But before you get excited, you'll find that it's completely unrelated to the Linux gettid(2). It returns the "per-thread override identity", which is a uid and gid that a thread might be operating under (like a per-thread setuid(2) kind of facility). No use to us.

If you poke a bit further, you'll find modern kernels have a thread_selfid(2) system call. This gives you the closest equivalent, but the numbers are going to be a lot larger than you're used to on Linux (they're 64-bit integers, and quite high). And this doesn't work on 10.5 or earlier (the system call was first implemented in 10.6).

Speaking of 10.6, there's also a non-portable pthread_threadid_np(3) that turns a pthread_t into a uint64_t. This gives the same values you'd get from thread_selfid(2). Again, this is unsupported in 10.5 and earlier.

So then there's always pthread_self(3). Sure, it returns an opaque type, but you know it's either going to be a thread id itself or, more likely, a pointer to some struct. So cast it to a suitably-sized integer and you're done. You might complain that the numbers are big and unwieldy, but so are your other choices. And at least these ones are portable, not just to old versions of Mac OS but to other OSes too. The values are somewhat useful in gdb(1) too.

The pthread_self(3) pthread_t isn't useful for a managed runtime's thin lock id, but then neither is Linux's gettid(2). If you really need something like that, you're going to have to follow your threads' life cycles and allocate and free ids yourself (either pid style or fd style, depending on whether you value avoiding reuse or smaller values more). So that's another option to consider if you'd like prettier, smaller "thread ids", albeit ones that have no meaning to other tools or parts of the system.

Anyway, here's some example code:
#include <errno.h>
#include <iostream>
#include <pthread.h>
#include <sys/syscall.h>

int main() {
 std::cout << "getpid()=" << getpid() << std::endl;

 std::cout << "pthread_self()=" << pthread_self() << std::endl;
 uint64_t tid;
 pthread_threadid_np(NULL, &tid);
 std::cout << "pthread_threadid_np()=" << tid << std::endl;

 std::cout << "syscall(SYS_thread_selfid)=" << syscall(SYS_thread_selfid) << std::endl;
 return 0;
}

And here's some corresponding example output from a 10.7 system:
getpid()=97626
pthread_self()=0x7fff7932e960
pthread_threadid_np()=2750350
syscall(SYS_thread_selfid)=2750350