Meditation, The Art of Exploitation

Thinking? At last I have discovered it--thought; this alone is inseparable from me. I am, I exist--that is certain. But for how long? For as long as I am thinking. For it could be, that were I totally to cease from thinking, I should totally cease to exist....I am, then, in the strict sense only a thing that thinks.

Tuesday, August 28, 2007

Another subtle difference between linux threads and posix threads, will the fun ever end?

During investigation of a black hole bug in a multi thread application, a fix is proposed to release a mutex locked by another thread. I thought this was a dubious idea as I remembered posix thread has the notion of mutex ownership. I checked 'Programming Posix Threads' and there it is. The author explicitly states (in the section discussing pthread_mutex_unlock), a mutex is owned by the thread that locked it and cannot be unlocked by another thread. But you should never trust what a book says on multi-threading issues. I decided to test this behavior and what you know, Linux threads does not honor pthread mutex ownership. Any thread can unlock any mutex locked by another thread. Here is the example code:


#include < stdlib.h>
#include < unistd.h>
#include < stdio.h>
#include < pthread.h>

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

void *
locker (void *blah)
{
int ret = pthread_mutex_lock(&m);
printf("lock mutex in locker: %d\n", ret);
sleep(10);
return 0;
}
void *
unlocker (void *blah)
{
sleep(3);
int ret = pthread_mutex_unlock(&m);
printf("unlock mutex not owned by locker: %d\n", ret);
ret = pthread_mutex_lock(&m);
printf("lock mutex in unlocker: %d\n", ret);
sleep(10);
return 0;
}

int main()
{
int result;
pthread_t tid[10000];
int count=0, oldc = 0;
pthread_attr_t new_child_attr;

result = pthread_attr_init (&new_child_attr);
result = pthread_attr_setdetachstate (&new_child_attr,
PTHREAD_CREATE_DETACHED);
// result = pthread_create (&tid[count], &new_child_attr, (void *(*)(void *)) locker, 0);
// result = pthread_create (&tid[count+1], &new_child_attr, (void *(*)(void *)) unlocker, 0);
result = pthread_create (&tid[count], 0, (void *(*)(void *)) locker, 0);
result = pthread_create (&tid[count+1], 0, (void *(*)(void *)) unlocker, 0);
pthread_join(tid[0], 0);
result = pthread_join(tid[1], 0);
printf("threads returned: %d\n", result);
sleep(30);
}