kern/24641: pthread_rwlock_rdlock can deadlock

Craig Rodrigues rodrigc at FreeBSD.org
Sun Jun 4 17:30:48 PDT 2006


Synopsis: pthread_rwlock_rdlock can deadlock

State-Changed-From-To: open->closed
State-Changed-By: rodrigc
State-Changed-When: Mon Jun 5 00:28:27 UTC 2006
State-Changed-Why: 
Problem does not occur in libpthread in FreeBSD 6.x.

Your testcase needs to be modified slightly.
If you call pthread_join(),
then if you call pthread_detach() later on, pthread_detach
may return EINVAL, because the thread may already be
terminated and detached, so you can't detach it.


#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
 
 static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER;
 
 static volatile int wrStarted;
 
 void * wrfunc(void *unused)
 {
    wrStarted = 1;

    printf("Attempt to acquire write lock\n");
    assert(pthread_rwlock_wrlock(&rwlock1) == 0);
    printf("Acquired write lock\n");
 
    assert(pthread_rwlock_unlock(&rwlock1) == 0);

    return 0;
 }
 
 static volatile int rdStarted;
 
 void * rdfunc(void *unused)
 {
    printf("Attempt to acquire read lock first\n");

    assert(pthread_rwlock_rdlock(&rwlock1) == 0);
    printf("Acquired read lock first\n");

    rdStarted = 1;

    while (wrStarted == 0)
        sleep(1);
 
    printf("Attempt to acquire read lock second\n");
    assert(pthread_rwlock_rdlock(&rwlock1) == 0);
    printf("Acquired read lock second\n");
 
    assert(pthread_rwlock_unlock(&rwlock1) == 0);
    assert(pthread_rwlock_unlock(&rwlock1) == 0);

    return 0;
 }
 
 int
 main(int argc, char **argv)
 {
    pthread_t wrt;
    pthread_t rdt;
    pthread_attr_t a;
    int ret;
 
    assert(pthread_rwlock_init(&rwlock1, 0) == 0);
 
    assert(pthread_attr_init(&a) == 0);
 
    assert(pthread_create(&rdt, &a, rdfunc, NULL) == 0);
 
    while (rdStarted == 0)
        sleep(1);
 
    assert(pthread_create(&wrt, &a, wrfunc, NULL) == 0);
 
   assert(pthread_join(wrt, 0) == 0);
   assert(pthread_join(rdt, 0) == 0);
 
    assert(pthread_rwlock_destroy(&rwlock1) == 0);
 
   if ((ret = pthread_detach(wrt)) != 0) {
	if (ret == EINVAL) {
		printf("wrt already detached\n");
	}
   }

  if ((ret = pthread_detach(rdt)) != 0) {
	if (errno == EINVAL) {
		printf("rdt already detached\n");
	}
  } 
    return 0;
 }
 

http://www.freebsd.org/cgi/query-pr.cgi?pr=24641


More information about the freebsd-threads mailing list