Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/security/nss/lib/util/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  nssrwlk.c   Sprache: C

 
/* 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 "nssrwlk.h"
#include "nspr.h"

PR_BEGIN_EXTERN_C

/*
 * Reader-writer lock
 */

struct nssRWLockStr {
    PZLock *rw_lock;
    char *rw_name;               /* lock name                    */
    PRUint32 rw_rank;            /* rank of the lock             */
    PRInt32 rw_writer_locks;     /* ==  0, if unlocked           */
    PRInt32 rw_reader_locks;     /* ==  0, if unlocked           */
                                 /* > 0  , # of read locks       */
    PRUint32 rw_waiting_readers; /* number of waiting readers    */
    PRUint32 rw_waiting_writers; /* number of waiting writers    */
    PZCondVar *rw_reader_waitq;  /* cvar for readers             */
    PZCondVar *rw_writer_waitq;  /* cvar for writers             */
    PRThread *rw_owner;          /* lock owner for write-lock    */
                                 /* Non-null if write lock held. */
};

PR_END_EXTERN_C

#include <string.h>

#ifdef DEBUG_RANK_ORDER
#define NSS_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using \
                                       rank-order for locks            \
                                    */

#endif

#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG

static PRUintn nss_thread_rwlock_initialized;
static PRUintn nss_thread_rwlock; /* TPD key for lock stack */
static PRUintn nss_thread_rwlock_alloc_failed;

#define _NSS_RWLOCK_RANK_ORDER_LIMIT 10

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

} thread_rwlock_stack;

/* forward static declarations. */
static PRUint32 nssRWLock_GetThreadRank(PRThread *me);
static void nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock);
static void nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock);
static void nssRWLock_ReleaseLockStack(void *lock_stack);

#endif

#define UNTIL(x) while (!(x))

/*
 * Reader/Writer Locks
 */


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


NSSRWLock *
NSSRWLock_New(PRUint32 lock_rank, const char *lock_name)
{
    NSSRWLock *rwlock;

    rwlock = PR_NEWZAP(NSSRWLock);
    if (rwlock == NULL)
        return NULL;

    rwlock->rw_lock = PZ_NewLock(nssILockRWLock);
    if (rwlock->rw_lock == NULL) {
        goto loser;
    }
    rwlock->rw_reader_waitq = PZ_NewCondVar(rwlock->rw_lock);
    if (rwlock->rw_reader_waitq == NULL) {
        goto loser;
    }
    rwlock->rw_writer_waitq = PZ_NewCondVar(rwlock->rw_lock);
    if (rwlock->rw_writer_waitq == NULL) {
        goto loser;
    }
    if (lock_name != NULL) {
        rwlock->rw_name = (char *)PR_Malloc((PRUint32)strlen(lock_name) + 1);
        if (rwlock->rw_name == NULL) {
            goto loser;
        }
        strcpy(rwlock->rw_name, lock_name);
    } else {
        rwlock->rw_name = NULL;
    }
    rwlock->rw_rank = lock_rank;
    rwlock->rw_waiting_readers = 0;
    rwlock->rw_waiting_writers = 0;
    rwlock->rw_reader_locks = 0;
    rwlock->rw_writer_locks = 0;

    return rwlock;

loser:
    NSSRWLock_Destroy(rwlock);
    return (NULL);
}

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

void
NSSRWLock_Destroy(NSSRWLock *rwlock)
{
    PR_ASSERT(rwlock != NULL);
    PR_ASSERT(rwlock->rw_waiting_readers == 0);
    PR_ASSERT(rwlock->rw_writer_locks == 0);
    PR_ASSERT(rwlock->rw_reader_locks == 0);

    /* XXX Shouldn't we lock the PZLock before destroying this?? */

    if (rwlock->rw_name)
        PR_Free(rwlock->rw_name);
    if (rwlock->rw_reader_waitq)
        PZ_DestroyCondVar(rwlock->rw_reader_waitq);
    if (rwlock->rw_writer_waitq)
        PZ_DestroyCondVar(rwlock->rw_writer_waitq);
    if (rwlock->rw_lock)
        PZ_DestroyLock(rwlock->rw_lock);
    PR_DELETE(rwlock);
}

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

void
NSSRWLock_LockRead(NSSRWLock *rwlock)
{
    PRThread *me = PR_GetCurrentThread();

    PZ_Lock(rwlock->rw_lock);
#ifdef NSS_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 == NSS_RWLOCK_RANK_NONE) ||
              (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
#endif
    /*
     * wait if write-locked or if a writer is waiting; preference for writers
     */

    UNTIL((rwlock->rw_owner == me) ||    /* I own it, or        */
          ((rwlock->rw_owner == NULL) && /* no-one owns it, and */
           (rwlock->rw_waiting_writers == 0)))
    { /* no-one is waiting to own */

        rwlock->rw_waiting_readers++;
        PZ_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
        rwlock->rw_waiting_readers--;
    }
    rwlock->rw_reader_locks++; /* Increment read-lock count */

    PZ_Unlock(rwlock->rw_lock);

#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
    nssRWLock_SetThreadRank(me, rwlock); /* update thread's lock rank */
#endif
}

/* Unlock a Read lock held on this RW lock.
 */

void
NSSRWLock_UnlockRead(NSSRWLock *rwlock)
{
    PZ_Lock(rwlock->rw_lock);

    PR_ASSERT(rwlock->rw_reader_locks > 0); /* lock must be read locked */

    if ((rwlock->rw_reader_locks > 0) &&    /* caller isn't screwey */
        (--rwlock->rw_reader_locks == 0) && /* not read locked any more */
        (rwlock->rw_owner == NULL) &&       /* not write locked */
        (rwlock->rw_waiting_writers > 0)) { /* someone's waiting. */

        PZ_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */
    }

    PZ_Unlock(rwlock->rw_lock);

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

    nssRWLock_UnsetThreadRank(me, rwlock);
#endif
    return;
}

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

void
NSSRWLock_LockWrite(NSSRWLock *rwlock)
{
    PRThread *me = PR_GetCurrentThread();

    PZ_Lock(rwlock->rw_lock);
#ifdef NSS_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 == NSS_RWLOCK_RANK_NONE) ||
              (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
#endif
    /*
     * wait if read locked or write locked.
     */

    PR_ASSERT(rwlock->rw_reader_locks >= 0);
    PR_ASSERT(me != NULL);

    UNTIL((rwlock->rw_owner == me) ||    /* I own write lock, or */
          ((rwlock->rw_owner == NULL) && /* no writer   and */
           (rwlock->rw_reader_locks == 0)))
    { /* no readers, either. */

        rwlock->rw_waiting_writers++;
        PZ_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
        rwlock->rw_waiting_writers--;
        PR_ASSERT(rwlock->rw_reader_locks >= 0);
    }

    PR_ASSERT(rwlock->rw_reader_locks == 0);
    /*
     * apply write lock
     */

    rwlock->rw_owner = me;
    rwlock->rw_writer_locks++; /* Increment write-lock count */

    PZ_Unlock(rwlock->rw_lock);

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

    nssRWLock_SetThreadRank(me, rwlock);
#endif
}

/* Unlock a Read lock held on this RW lock.
 */

void
NSSRWLock_UnlockWrite(NSSRWLock *rwlock)
{
    PRThread *me = PR_GetCurrentThread();

    PZ_Lock(rwlock->rw_lock);
    PR_ASSERT(rwlock->rw_owner == me);      /* lock must be write-locked by me.  */
    PR_ASSERT(rwlock->rw_writer_locks > 0); /* lock must be write locked */

    if (rwlock->rw_owner == me &&         /* I own it, and            */
        rwlock->rw_writer_locks > 0 &&    /* I own it, and            */
        --rwlock->rw_writer_locks == 0) { /* I'm all done with it     */

        rwlock->rw_owner = NULL; /* I don't own it any more. */

        /* Give preference to waiting writers. */
        if (rwlock->rw_waiting_writers > 0) {
            if (rwlock->rw_reader_locks == 0)
                PZ_NotifyCondVar(rwlock->rw_writer_waitq);
        } else if (rwlock->rw_waiting_readers > 0) {
            PZ_NotifyAllCondVar(rwlock->rw_reader_waitq);
        }
    }
    PZ_Unlock(rwlock->rw_lock);

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

    nssRWLock_UnsetThreadRank(me, rwlock);
#endif
    return;
}

/* This is primarily for debugging, i.e. for inclusion in ASSERT calls. */
PRBool
NSSRWLock_HaveWriteLock(NSSRWLock *rwlock)
{
    PRBool ownWriteLock;
    PRThread *me = PR_GetCurrentThread();

/* This lock call isn't really necessary.
 ** If this thread is the owner, that fact cannot change during this call,
 ** because this thread is in this call.
 ** If this thread is NOT the owner, the owner could change, but it
 ** could not become this thread.
 */

#if UNNECESSARY
    PZ_Lock(rwlock->rw_lock);
#endif
    ownWriteLock = (PRBool)(me == rwlock->rw_owner);
#if UNNECESSARY
    PZ_Unlock(rwlock->rw_lock);
#endif
    return ownWriteLock;
}

#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG

/*
 * nssRWLock_SetThreadRank
 *      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
nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock)
{
    thread_rwlock_stack *lock_stack;
    PRStatus rv;

    /*
     * allocated thread-private-data for rwlock list, if not already allocated
     */

    if (!nss_thread_rwlock_initialized) {
        /*
         * allocate tpd, only if not failed already
         */

        if (!nss_thread_rwlock_alloc_failed) {
            if (PR_NewThreadPrivateIndex(&nss_thread_rwlock,
                                         nssRWLock_ReleaseLockStack) == PR_FAILURE) {
                nss_thread_rwlock_alloc_failed = 1;
                return;
            }
        } else
            return;
    }
    /*
     * allocate a lock stack
     */

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

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

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

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


static PRUint32
nssRWLock_GetThreadRank(PRThread *me)
{
    thread_rwlock_stack *lock_stack;

    if (nss_thread_rwlock_initialized) {
        if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL)
            return (NSS_RWLOCK_RANK_NONE);
        else
            return (lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);

    } else
        return (NSS_RWLOCK_RANK_NONE);
}

/*
 * nssRWLock_UnsetThreadRank
 *
 *      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
nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock)
{
    thread_rwlock_stack *lock_stack;
    int new_index = 0, index, done = 0;

    if (!nss_thread_rwlock_initialized)
        return;

    lock_stack = PR_GetThreadPrivate(nss_thread_rwlock);

    PR_ASSERT(lock_stack != NULL);

    index = lock_stack->trs_index - 1;
    while (index-- >= 0) {
        if ((lock_stack->trs_stack[index] == rwlock) && !done) {
            /*
             * 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 ((lock_stack->trs_stack[index] != NULL) && !new_index)
            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 /* NSS_RWLOCK_RANK_ORDER_DEBUG */

Messung V0.5
C=94 H=96 G=94

¤ 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.