I am running a phread test program until it fails. Here is the main skeleton of the code:
int authSessionListMutexUnlock()
{
int rc = 0;
int rc2 = 0;
rc2 = pthread_mutex_trylock(&mutex);
ERR_IF( rc2 != EBUSY && rc2 != 0 );
rc2 = pthread_mutex_unlock(&mutex);
ERR_IF( rc2 != 0 );
cleanup:
return rc;
}
static void cleanup_handler(void *arg)
{
int rc = 0;
(void)arg;
rc = authSessionListMutexUnlock();
if (rc != 0)
AUTH_DEBUG5("authSessionListMutexUnlock() failed\n");
}
static void *destroy_expired_sessions(void *t)
{
int rc2 = 0;
(void)t;
pthread_cleanup_push(cleanup_handler, NULL);
rc2 = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (rc2 != 0)
AUTH_DEBUG5("pthread_setcancelstate(): rc2 == %d\n", rc2);
rc2 = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (rc2 != 0)
AUTH_DEBUG5("pthread_setcanceltype(): rc2 == %d\n", rc2);
while (1)
{
... // destroy expired session
sleep(min_timeout);
}
pthread_cleanup_pop(0);
}
int authDeinit( char *path )
{
...
rc2 = authSessionListDeInit();
ERR_IF( rc2 != 0 );
rc2 = pthread_cancel(destroy_thread);
ERR_IF( rc2 != 0 );
rc2 = pthread_join(destroy_thread, &status);
ERR_IF( rc2 != 0 || (int *)status != PTHREAD_CANCELED );
...
return 0
}
It runs well with the test program, but the test program hangs at round #53743 with pthread_join():
(gdb) bt
#0 0x40000410 in __kernel_vsyscall ()
#1 0x0094aa77 in pthread_join () from /lib/libpthread.so.0
#2 0x08085745 in authDeinit ()
at /users/qixu/src/moja/auth/src//app/libauth/authAPI.c:1562
#3 0x0807e747 in main ()
at /users/qixu/src/moja/auth/src//app/tests/test_session.c:45
Looks like pthread_join() caused a deadlock. But looking at the code, I feel there is no reason that a dead lock be caused by pthread_join(). When pthread_join() gets the chance to run, the only mutex operation is of the thread itself. Should be no conflict, right? Really confused here…
At least one “oddity” shows in your code; your cleanup handler will always unlock the mutex even if you’re not the thread holding it.
From the manual;