threads/136345: Recursive read rwlocks in thread A cause deadlock with write lock in thread B

Rink Springer rink at
Sun Jul 5 14:00:11 UTC 2009

>Number:         136345
>Category:       threads
>Synopsis:       Recursive read rwlocks in thread A cause deadlock with write lock in thread B
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-threads
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jul 05 14:00:10 UTC 2009
>Originator:     Rink Springer
>Release:        FreeBSD 7.2-PRERELEASE amd64
System: FreeBSD 7.2-PRERELEASE FreeBSD 7.2-PRERELEASE #1 r191417: Thu Apr 23 13:53:08 CEST 2009 rink at amd64

The problem is also present in HEAD as of today.

The following program deadlocks on FreeBSD in the 'urdlck' state:

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

pthread_rwlock_t rwl_lock;

thread1(void* x)
	while(1) {


	return NULL;

thread2(void* x)
	while(1) {



	return NULL;

	pthread_t thr_1, thr_2;

	pthread_rwlock_init(&rwl_lock, NULL);

	pthread_create(&thr_1, NULL, thread1, NULL);
	pthread_create(&thr_1, NULL, thread2, NULL);

	pthread_join(thr_1, NULL);
	return 0;

The problem is that it acquires a read rwlock multiple times in one thread, and tries to acquire a write rwlock in another thread.

$ gcc -o locktest locktest.c -pthread
$ ./locktest
... output ...
load: 0.00  cmd: locktest 72866 [urdlck] 1.38r 0.01u 0.00s 0% 1360k

and it's deadlocked. Note that POSIX states that 'A thread may hold multiple concurrent read locks on rwlock (that is, successfully call the pthread_rwlock_rdlock() function n times). If so, the application shall ensure that the thread performs matching unlocks (that is, it calls the pthread_rwlock_unlock() function n times).', which seems to imply that the program above shouldn't deadlock.

The program above works fine on Linux, yet it also seems to deadlock on Solaris 8. I have yet to check more recent versions of Solaris.

Don't Do That[tm]; it seems the only fix is to restructure the application to avoid this scenario, even though POSIX seems to allow it.

More information about the freebsd-threads mailing list