Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/nsprpub/pr/src/threads/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 11 kB image not shown  

Quelle  prrwlock.c   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "primpl.h"

#include <string.h>

#if defined(HPUX) && defined(_PR_PTHREADS)

#  include <pthread.h>
#  define HAVE_UNIX98_RWLOCK
#  define RWLOCK_T pthread_rwlock_t
#  define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
#  define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock)
#  define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
#  define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
#  define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock)

#elif defined(SOLARIS) && \
    (defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY))

#  include <synch.h>
#  define HAVE_UI_RWLOCK
#  define RWLOCK_T rwlock_t
#  define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL)
#  define RWLOCK_DESTROY(lock) rwlock_destroy(lock)
#  define RWLOCK_RDLOCK(lock) rw_rdlock(lock)
#  define RWLOCK_WRLOCK(lock) rw_wrlock(lock)
#  define RWLOCK_UNLOCK(lock) rw_unlock(lock)

#endif

/*
 * Reader-writer lock
 */

struct PRRWLock {
  char* rw_name;    /* lock name                    */
  PRUint32 rw_rank; /* rank of the lock             */

#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  RWLOCK_T rw_lock;
#else
  PRLock* rw_lock;
  PRInt32 rw_lock_cnt; /* ==  0, if unlocked           */
  /* == -1, if write-locked       */
  /* > 0  , # of read locks       */
  PRUint32 rw_reader_cnt;     /* number of waiting readers    */
  PRUint32 rw_writer_cnt;     /* number of waiting writers    */
  PRCondVar* rw_reader_waitq; /* cvar for readers             */
  PRCondVar* rw_writer_waitq; /* cvar for writers             */
#  ifdef DEBUG
  PRThread* rw_owner; /* lock owner for write-lock    */
#  endif
#endif
};

#ifdef DEBUG
#  define _PR_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using \
                                         rank-order for locks            \
                                      */

#endif

#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG

static PRUintn pr_thread_rwlock_key; /* TPD key for lock stack */
static PRUintn pr_thread_rwlock_alloc_failed;

#  define _PR_RWLOCK_RANK_ORDER_LIMIT 10

typedef struct thread_rwlock_stack {
  PRInt32 trs_index;                                /* top of stack */
  PRRWLock* trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock
                                                       pointers */


} thread_rwlock_stack;

static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock* rwlock);
static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void);
static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock* rwlock);
static void _PR_RELEASE_LOCK_STACK(void* lock_stack);

#endif

/*
 * Reader/Writer Locks
 */


/*
 * PR_NewRWLock
 *      Create a reader-writer lock, with the given lock rank and lock name
 *
 */


PR_IMPLEMENT(PRRWLock*)
PR_NewRWLock(PRUint32 lock_rank, const char* lock_name) {
  PRRWLock* rwlock;
#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  int err;
#endif

  if (!_pr_initialized) {
    _PR_ImplicitInitialization();
  }

  rwlock = PR_NEWZAP(PRRWLock);
  if (rwlock == NULL) {
    return NULL;
  }

  rwlock->rw_rank = lock_rank;
  if (lock_name != NULL) {
    rwlock->rw_name = (char*)PR_Malloc(strlen(lock_name) + 1);
    if (rwlock->rw_name == NULL) {
      PR_DELETE(rwlock);
      return (NULL);
    }
    strcpy(rwlock->rw_name, lock_name);
  } else {
    rwlock->rw_name = NULL;
  }

#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  err = RWLOCK_INIT(&rwlock->rw_lock);
  if (err != 0) {
    PR_SetError(PR_UNKNOWN_ERROR, err);
    PR_Free(rwlock->rw_name);
    PR_DELETE(rwlock);
    return NULL;
  }
  return rwlock;
#else
  rwlock->rw_lock = PR_NewLock();
  if (rwlock->rw_lock == NULL) {
    goto failed;
  }
  rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock);
  if (rwlock->rw_reader_waitq == NULL) {
    goto failed;
  }
  rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock);
  if (rwlock->rw_writer_waitq == NULL) {
    goto failed;
  }
  rwlock->rw_reader_cnt = 0;
  rwlock->rw_writer_cnt = 0;
  rwlock->rw_lock_cnt = 0;
  return rwlock;

failed:
  if (rwlock->rw_reader_waitq != NULL) {
    PR_DestroyCondVar(rwlock->rw_reader_waitq);
  }
  if (rwlock->rw_lock != NULL) {
    PR_DestroyLock(rwlock->rw_lock);
  }
  PR_Free(rwlock->rw_name);
  PR_DELETE(rwlock);
  return NULL;
#endif
}

/*
** Destroy the given RWLock "lock".
*/

PR_IMPLEMENT(void)
PR_DestroyRWLock(PRRWLock* rwlock) {
#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  int err;
  err = RWLOCK_DESTROY(&rwlock->rw_lock);
  PR_ASSERT(err == 0);
#else
  PR_ASSERT(rwlock->rw_reader_cnt == 0);
  PR_DestroyCondVar(rwlock->rw_reader_waitq);
  PR_DestroyCondVar(rwlock->rw_writer_waitq);
  PR_DestroyLock(rwlock->rw_lock);
#endif
  if (rwlock->rw_name != NULL) {
    PR_Free(rwlock->rw_name);
  }
  PR_DELETE(rwlock);
}

/*
** Read-lock the RWLock.
*/

PR_IMPLEMENT(void)
PR_RWLock_Rlock(PRRWLock* rwlock) {
#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  int err;
#endif

#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
  /*
   * assert that rank ordering is not violated; the rank of 'rwlock' should
   * be equal to or greater than the highest rank of all the locks held by
   * the thread.
   */

  PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) ||
            (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
#endif

#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  err = RWLOCK_RDLOCK(&rwlock->rw_lock);
  PR_ASSERT(err == 0);
#else
  PR_Lock(rwlock->rw_lock);
  /*
   * wait if write-locked or if a writer is waiting; preference for writers
   */

  while ((rwlock->rw_lock_cnt < 0) || (rwlock->rw_writer_cnt > 0)) {
    rwlock->rw_reader_cnt++;
    PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
    rwlock->rw_reader_cnt--;
  }
  /*
   * Increment read-lock count
   */

  rwlock->rw_lock_cnt++;

  PR_Unlock(rwlock->rw_lock);
#endif

#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
  /*
   * update thread's lock rank
   */

  if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE) {
    _PR_SET_THREAD_RWLOCK_RANK(rwlock);
  }
#endif
}

/*
** Write-lock the RWLock.
*/

PR_IMPLEMENT(void)
PR_RWLock_Wlock(PRRWLock* rwlock) {
#if defined(DEBUG)
  PRThread* me = PR_GetCurrentThread();
#endif
#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  int err;
#endif

#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
  /*
   * assert that rank ordering is not violated; the rank of 'rwlock' should
   * be equal to or greater than the highest rank of all the locks held by
   * the thread.
   */

  PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) ||
            (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
#endif

#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  err = RWLOCK_WRLOCK(&rwlock->rw_lock);
  PR_ASSERT(err == 0);
#else
  PR_Lock(rwlock->rw_lock);
  /*
   * wait if read locked
   */

  while (rwlock->rw_lock_cnt != 0) {
    rwlock->rw_writer_cnt++;
    PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
    rwlock->rw_writer_cnt--;
  }
  /*
   * apply write lock
   */

  rwlock->rw_lock_cnt--;
  PR_ASSERT(rwlock->rw_lock_cnt == -1);
#  ifdef DEBUG
  PR_ASSERT(me != NULL);
  rwlock->rw_owner = me;
#  endif
  PR_Unlock(rwlock->rw_lock);
#endif

#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
  /*
   * update thread's lock rank
   */

  if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE) {
    _PR_SET_THREAD_RWLOCK_RANK(rwlock);
  }
#endif
}

/*
** Unlock the RW lock.
*/

PR_IMPLEMENT(void)
PR_RWLock_Unlock(PRRWLock* rwlock) {
#if defined(DEBUG)
  PRThread* me = PR_GetCurrentThread();
#endif
#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  int err;
#endif

#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
  err = RWLOCK_UNLOCK(&rwlock->rw_lock);
  PR_ASSERT(err == 0);
#else
  PR_Lock(rwlock->rw_lock);
  /*
   * lock must be read or write-locked
   */

  PR_ASSERT(rwlock->rw_lock_cnt != 0);
  if (rwlock->rw_lock_cnt > 0) {
    /*
     * decrement read-lock count
     */

    rwlock->rw_lock_cnt--;
    if (rwlock->rw_lock_cnt == 0) {
      /*
       * lock is not read-locked anymore; wakeup a waiting writer
       */

      if (rwlock->rw_writer_cnt > 0) {
        PR_NotifyCondVar(rwlock->rw_writer_waitq);
      }
    }
  } else {
    PR_ASSERT(rwlock->rw_lock_cnt == -1);

    rwlock->rw_lock_cnt = 0;
#  ifdef DEBUG
    PR_ASSERT(rwlock->rw_owner == me);
    rwlock->rw_owner = NULL;
#  endif
    /*
     * wakeup a writer, if present; preference for writers
     */

    if (rwlock->rw_writer_cnt > 0) {
      PR_NotifyCondVar(rwlock->rw_writer_waitq);
    }
    /*
     * else, wakeup all readers, if any
     */

    else if (rwlock->rw_reader_cnt > 0) {
      PR_NotifyAllCondVar(rwlock->rw_reader_waitq);
    }
  }
  PR_Unlock(rwlock->rw_lock);
#endif

#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
  /*
   * update thread's lock rank
   */

  if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE) {
    _PR_UNSET_THREAD_RWLOCK_RANK(rwlock);
  }
#endif
  return;
}

#ifndef _PR_RWLOCK_RANK_ORDER_DEBUG

void _PR_InitRWLocks(void) {}

#else

void _PR_InitRWLocks(void) {
  /*
   * allocated thread-private-data index for rwlock list
   */

  if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key, _PR_RELEASE_LOCK_STACK) ==
      PR_FAILURE) {
    pr_thread_rwlock_alloc_failed = 1;
    return;
  }
}

/*
 * _PR_SET_THREAD_RWLOCK_RANK
 *      Set a thread's lock rank, which is the highest of the ranks of all
 *      the locks held by the thread. Pointers to the locks are added to a
 *      per-thread list, which is anchored off a thread-private data key.
 */


static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock* rwlock) {
  thread_rwlock_stack* lock_stack;
  PRStatus rv;

  /*
   * allocate a lock stack
   */

  if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) {
    lock_stack =
        (thread_rwlock_stack*)PR_CALLOC(1 * sizeof(thread_rwlock_stack));
    if (lock_stack) {
      rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack);
      if (rv == PR_FAILURE) {
        PR_DELETE(lock_stack);
        pr_thread_rwlock_alloc_failed = 1;
        return;
      }
    } else {
      pr_thread_rwlock_alloc_failed = 1;
      return;
    }
  }
  /*
   * add rwlock to lock stack, if limit is not exceeded
   */

  if (lock_stack) {
    if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT) {
      lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;
    }
  }
}

static void _PR_RELEASE_LOCK_STACK(void* lock_stack) {
  PR_ASSERT(lock_stack);
  PR_DELETE(lock_stack);
}

/*
 * _PR_GET_THREAD_RWLOCK_RANK
 *
 *      return thread's lock rank. If thread-private-data for the lock
 *      stack is not allocated, return PR_RWLOCK_RANK_NONE.
 */


static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void) {
  thread_rwlock_stack* lock_stack;

  lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
  if (lock_stack == NULL || lock_stack->trs_index == 0) {
    return (PR_RWLOCK_RANK_NONE);
  } else {
    return (lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
  }
}

/*
 * _PR_UNSET_THREAD_RWLOCK_RANK
 *
 *      remove the rwlock from the lock stack. Since locks may not be
 *      unlocked in a FIFO order, the entire lock stack is searched.
 */


static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock* rwlock) {
  thread_rwlock_stack* lock_stack;
  int new_index = 0, index, done = 0;

  lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);

  PR_ASSERT(lock_stack != NULL);

  for (index = lock_stack->trs_index - 1; index >= 0; index--) {
    if (!done && (lock_stack->trs_stack[index] == rwlock)) {
      /*
       * reset the slot for rwlock
       */

      lock_stack->trs_stack[index] = NULL;
      done = 1;
    }
    /*
     * search for the lowest-numbered empty slot, above which there are
     * no non-empty slots
     */

    if (!new_index && (lock_stack->trs_stack[index] != NULL)) {
      new_index = index + 1;
    }
    if (done && new_index) {
      break;
    }
  }
  /*
   * set top of stack to highest numbered empty slot
   */

  lock_stack->trs_index = new_index;
}

#endif /* _PR_RWLOCK_RANK_ORDER_DEBUG */

Messung V0.5
C=95 H=98 G=96

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.