Sunday, June 17, 2012

Linux Thread ID

There is some useful and interesting book about Linux programming, freely available in network: Advanced Linux Programming. One of outdated topics of this book is 4.5 GNU/Linux Thread Implementation. Book says that on GNU/Linux threads are implemented as processes. Next code should confirm that, but it is not do it for now:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *thread_fun(void *arg)
{
    fprintf(stderr, "child thread pid is %d\n", (int)getpid());
    while(1);
    return NULL;
}

int main(void)
{
    pthread_t thread;
    fprintf(stderr, "main thread pid is %d\n", (int)getpid());
    pthread_create(&thread, NULL, &thread_fun, NULL);
    while(1);
    return 0;
}

So, instead of different process ID's we have one:

$ ./alp-thread-pid
main thread pid is 17280
child thread pid is 17280

How can we get thread ID? We can find simple function pthread_t pthread_self(void); in <pthread.h>. We must use this function, if we write portable program. This thread IDs are only guaranteed to be unique within a process, but may be reused after a terminated thread has been joined, or a detached thread has terminated. Value, returned by pthread_self, has opaque type - POSIX.1 allows it to be arithmetic type or a structure. So, we cannot print it if we don't know how implementation represents it.
However, Linux kernel uses its own thread identification. We can get kernel thread ID by call pid_t gettid(void); in <sys/types.h>; But glibc does not provide a wrapper for this system call! So, let's write it ourself and print it:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

pid_t gettid(void)
{
    return syscall(SYS_gettid);
}

void *thread_fun(void *arg)
{
    fprintf(stderr, "child thread pid is %d\n", (int)getpid());
    fprintf(stderr, "child kernel thread tid is %d\n", (int)gettid());
    while(1);
    return NULL;
}

int main(void)
{
    pthread_t thread;
    fprintf(stderr, "main thread pid is %d\n", (int)getpid());
    fprintf(stderr, "main kernel thread tid is %d\n", (int)gettid());
    pthread_create(&thread, NULL, &thread_fun, NULL);
    while(1);
    return 0;
}

Run it:

$ ./thread-pid 
main thread pid is 18866
main kernel thread tid is 18866
child thread pid is 18866
child kernel thread tid is 18867

We found our TID!