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

Rink Springer rink at FreeBSD.org
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
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jul 05 14:00:10 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Rink Springer
>Release:        FreeBSD 7.2-PRERELEASE amd64
>Organization:
>Environment:
System: FreeBSD gloom.rink.nu 7.2-PRERELEASE FreeBSD 7.2-PRERELEASE #1 r191417: Thu Apr 23 13:53:08 CEST 2009 rink at gloom.rink.nu:/usr/obj/extra0/sources/releng7/sys/GENERIC amd64

The problem is also present in HEAD as of today.

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

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

pthread_rwlock_t rwl_lock;

void*
thread1(void* x)
{
	while(1) {
		pthread_rwlock_rdlock(&rwl_lock);
		printf("read1\n");
		pthread_rwlock_rdlock(&rwl_lock);
		printf("read2\n");

		pthread_rwlock_unlock(&rwl_lock);
		pthread_rwlock_unlock(&rwl_lock);

	}
	return NULL;
}

void*
thread2(void* x)
{
	while(1) {
		pthread_rwlock_wrlock(&rwl_lock);

		printf("write\n");

		pthread_rwlock_unlock(&rwl_lock);

	}
	return NULL;
}

int
main()
{
	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.

>How-To-Repeat:
$ 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.

>Fix:
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.
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-threads mailing list