Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 25 Jan 2001 09:48:08 -0800 (PST)
From:      earl_chew@agilent.com
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   misc/24641: pthread_rwlock_rdlock can deadlock
Message-ID:  <200101251748.f0PHm8B52012@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help


>Number:         24641
>Category:       misc
>Synopsis:       pthread_rwlock_rdlock can deadlock
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 25 09:50:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Earl Chew
>Release:        3.3-RELEASE
>Organization:
Agilent Technologies
>Environment:
FreeBSD qar1 3.3-RELEASE FreeBSD 3.3-RELEASE #0: Tue Oct 17 16:21:01 EDT 2000
>Description:
The man page for pthread_rwlock_rdlock() says:

   A thread may hold multiple concurrent read locks.  If so,
   pthread_rwlock_unlock() must be called once for each lock obtained.

I tried this out after reading Bill Lewis' article on Usenet:
http://x64.deja.com/[ST_rn=ps]/getdoc.xp?AN=573590892&search=thread&CONTEXT=980444523.1181483044&HIT_CONTEXT=980444500.1181483040&HIT_NUM=11&hitnum=3

Bill wrote:

    Consider: T1 gets a read lock. T2 wants a write
    lock & blocks, waiting for T1. Now T1 wants a read
    lock again. Because writers have priority, T1 will
    now block, waiting for T2.

My test program prints the following, then gets stuck:

    > ./a.out
    Attempt to acquire read lock first
    Acquired read lock first
    Attempt to acquire write lock
    Attempt to acquire read lock second

Examining the source code (uthread_rwlock.c,v 1.5) it is pretty
clear why this deadlock occurs (as Bill Lewis predicts).

>How-To-Repeat:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>

static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER;

static volatile int wrStarted;

void * wrfunc(void *)
{
  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 *)
{
  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, char**)
{
  pthread_t wrt;
  pthread_t rdt;
  pthread_attr_t a;

  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);

  assert(pthread_detach(wrt) == 0);
  assert(pthread_detach(rdt) == 0);

  return 0;
}

>Fix:


>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101251748.f0PHm8B52012>