LCOV - code coverage report
Current view: top level - nsprpub/pr/src/threads - prrwlock.c (source / functions) Hit Total Coverage
Test: output.info Lines: 2 128 1.6 %
Date: 2017-07-14 16:53:18 Functions: 1 5 20.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "primpl.h"
       7             : 
       8             : #include <string.h>
       9             : 
      10             : #if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
      11             : 
      12             : #include <pthread.h>
      13             : #define HAVE_UNIX98_RWLOCK
      14             : #define RWLOCK_T pthread_rwlock_t
      15             : #define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
      16             : #define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock)
      17             : #define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
      18             : #define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
      19             : #define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock)
      20             : 
      21             : #elif defined(SOLARIS) && (defined(_PR_PTHREADS) \
      22             :         || defined(_PR_GLOBAL_THREADS_ONLY))
      23             : 
      24             : #include <synch.h>
      25             : #define HAVE_UI_RWLOCK
      26             : #define RWLOCK_T rwlock_t
      27             : #define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL)
      28             : #define RWLOCK_DESTROY(lock) rwlock_destroy(lock)
      29             : #define RWLOCK_RDLOCK(lock) rw_rdlock(lock)
      30             : #define RWLOCK_WRLOCK(lock) rw_wrlock(lock)
      31             : #define RWLOCK_UNLOCK(lock) rw_unlock(lock)
      32             : 
      33             : #endif
      34             : 
      35             : /*
      36             :  * Reader-writer lock
      37             :  */
      38             : struct PRRWLock {
      39             :         char                    *rw_name;                       /* lock name                                    */
      40             :         PRUint32                rw_rank;                        /* rank of the lock                             */
      41             : 
      42             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
      43             :         RWLOCK_T                rw_lock;
      44             : #else
      45             :     PRLock                      *rw_lock;
      46             :         PRInt32                 rw_lock_cnt;            /* ==  0, if unlocked                   */
      47             :                                                                                 /* == -1, if write-locked               */
      48             :                                                                                 /* > 0       , # of read locks               */
      49             :         PRUint32                rw_reader_cnt;          /* number of waiting readers    */
      50             :         PRUint32                rw_writer_cnt;          /* number of waiting writers    */
      51             :         PRCondVar       *rw_reader_waitq;       /* cvar for readers                     */
      52             :         PRCondVar       *rw_writer_waitq;       /* cvar for writers                             */
      53             : #ifdef DEBUG
      54             :     PRThread            *rw_owner;                      /* lock owner for write-lock    */
      55             : #endif
      56             : #endif
      57             : };
      58             : 
      59             : #ifdef DEBUG
      60             : #define _PR_RWLOCK_RANK_ORDER_DEBUG     /* enable deadlock detection using
      61             :                                                                            rank-order for locks
      62             :                                                                         */
      63             : #endif
      64             : 
      65             : #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
      66             : 
      67             : static PRUintn  pr_thread_rwlock_key;                   /* TPD key for lock stack */
      68             : static PRUintn  pr_thread_rwlock_alloc_failed;
      69             : 
      70             : #define _PR_RWLOCK_RANK_ORDER_LIMIT     10
      71             : 
      72             : typedef struct thread_rwlock_stack {
      73             :         PRInt32         trs_index;                                                                      /* top of stack */
      74             :         PRRWLock        *trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT];        /* stack of lock
      75             :                                                                                                                            pointers */
      76             : 
      77             : } thread_rwlock_stack;
      78             : 
      79             : static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
      80             : static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void);
      81             : static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
      82             : static void _PR_RELEASE_LOCK_STACK(void *lock_stack);
      83             : 
      84             : #endif
      85             : 
      86             : /*
      87             :  * Reader/Writer Locks
      88             :  */
      89             : 
      90             : /*
      91             :  * PR_NewRWLock
      92             :  *              Create a reader-writer lock, with the given lock rank and lock name
      93             :  *      
      94             :  */
      95             : 
      96             : PR_IMPLEMENT(PRRWLock *)
      97             : PR_NewRWLock(PRUint32 lock_rank, const char *lock_name)
      98             : {
      99             :     PRRWLock *rwlock;
     100             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     101             :         int err;
     102             : #endif
     103             : 
     104           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
     105             : 
     106           0 :     rwlock = PR_NEWZAP(PRRWLock);
     107           0 :     if (rwlock == NULL)
     108           0 :                 return NULL;
     109             : 
     110           0 :         rwlock->rw_rank = lock_rank;
     111           0 :         if (lock_name != NULL) {
     112           0 :                 rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
     113           0 :         if (rwlock->rw_name == NULL) {
     114           0 :                         PR_DELETE(rwlock);
     115           0 :                         return(NULL);
     116             :                 }
     117           0 :                 strcpy(rwlock->rw_name, lock_name);
     118             :         } else {
     119           0 :                 rwlock->rw_name = NULL;
     120             :         }
     121             :         
     122             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     123             :         err = RWLOCK_INIT(&rwlock->rw_lock);
     124             :         if (err != 0) {
     125             :                 PR_SetError(PR_UNKNOWN_ERROR, err);
     126             :                 PR_Free(rwlock->rw_name);
     127             :                 PR_DELETE(rwlock);
     128             :                 return NULL;
     129             :         }
     130             :         return rwlock;
     131             : #else
     132           0 :         rwlock->rw_lock = PR_NewLock();
     133           0 :     if (rwlock->rw_lock == NULL) {
     134           0 :                 goto failed;
     135             :         }
     136           0 :         rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock);
     137           0 :     if (rwlock->rw_reader_waitq == NULL) {
     138           0 :                 goto failed;
     139             :         }
     140           0 :         rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock);
     141           0 :     if (rwlock->rw_writer_waitq == NULL) {
     142           0 :                 goto failed;
     143             :         }
     144           0 :         rwlock->rw_reader_cnt = 0;
     145           0 :         rwlock->rw_writer_cnt = 0;
     146           0 :         rwlock->rw_lock_cnt = 0;
     147           0 :         return rwlock;
     148             : 
     149             : failed:
     150           0 :         if (rwlock->rw_reader_waitq != NULL) {
     151           0 :                 PR_DestroyCondVar(rwlock->rw_reader_waitq);  
     152             :         }
     153           0 :         if (rwlock->rw_lock != NULL) {
     154           0 :                 PR_DestroyLock(rwlock->rw_lock);
     155             :         }
     156           0 :         PR_Free(rwlock->rw_name);
     157           0 :         PR_DELETE(rwlock);
     158           0 :         return NULL;
     159             : #endif
     160             : }
     161             : 
     162             : /*
     163             : ** Destroy the given RWLock "lock".
     164             : */
     165             : PR_IMPLEMENT(void)
     166             : PR_DestroyRWLock(PRRWLock *rwlock)
     167             : {
     168             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     169             :         int err;
     170             :         err = RWLOCK_DESTROY(&rwlock->rw_lock);
     171             :         PR_ASSERT(err == 0);
     172             : #else
     173           0 :         PR_ASSERT(rwlock->rw_reader_cnt == 0);
     174           0 :         PR_DestroyCondVar(rwlock->rw_reader_waitq);  
     175           0 :         PR_DestroyCondVar(rwlock->rw_writer_waitq);  
     176           0 :         PR_DestroyLock(rwlock->rw_lock);
     177             : #endif
     178           0 :         if (rwlock->rw_name != NULL)
     179           0 :                 PR_Free(rwlock->rw_name);
     180           0 :     PR_DELETE(rwlock);
     181           0 : }
     182             : 
     183             : /*
     184             : ** Read-lock the RWLock.
     185             : */
     186             : PR_IMPLEMENT(void)
     187             : PR_RWLock_Rlock(PRRWLock *rwlock)
     188             : {
     189             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     190             : int err;
     191             : #endif
     192             : 
     193             : #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
     194             :         /*
     195             :          * assert that rank ordering is not violated; the rank of 'rwlock' should
     196             :          * be equal to or greater than the highest rank of all the locks held by
     197             :          * the thread.
     198             :          */
     199           0 :         PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || 
     200             :                                         (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
     201             : #endif
     202             : 
     203             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     204             :         err = RWLOCK_RDLOCK(&rwlock->rw_lock);
     205             :         PR_ASSERT(err == 0);
     206             : #else
     207           0 :         PR_Lock(rwlock->rw_lock);
     208             :         /*
     209             :          * wait if write-locked or if a writer is waiting; preference for writers
     210             :          */
     211           0 :         while ((rwlock->rw_lock_cnt < 0) ||
     212           0 :                         (rwlock->rw_writer_cnt > 0)) {
     213           0 :                 rwlock->rw_reader_cnt++;
     214           0 :                 PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
     215           0 :                 rwlock->rw_reader_cnt--;
     216             :         }
     217             :         /*
     218             :          * Increment read-lock count
     219             :          */
     220           0 :         rwlock->rw_lock_cnt++;
     221             : 
     222           0 :         PR_Unlock(rwlock->rw_lock);
     223             : #endif
     224             : 
     225             : #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
     226             :         /*
     227             :          * update thread's lock rank
     228             :          */
     229           0 :         if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
     230           0 :                 _PR_SET_THREAD_RWLOCK_RANK(rwlock);
     231             : #endif
     232           0 : }
     233             : 
     234             : /*
     235             : ** Write-lock the RWLock.
     236             : */
     237             : PR_IMPLEMENT(void)
     238             : PR_RWLock_Wlock(PRRWLock *rwlock)
     239             : {
     240             : #if defined(DEBUG)
     241           0 : PRThread *me = PR_GetCurrentThread();
     242             : #endif
     243             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     244             : int err;
     245             : #endif
     246             : 
     247             : #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
     248             :         /*
     249             :          * assert that rank ordering is not violated; the rank of 'rwlock' should
     250             :          * be equal to or greater than the highest rank of all the locks held by
     251             :          * the thread.
     252             :          */
     253           0 :         PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || 
     254             :                                         (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
     255             : #endif
     256             : 
     257             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     258             :         err = RWLOCK_WRLOCK(&rwlock->rw_lock);
     259             :         PR_ASSERT(err == 0);
     260             : #else
     261           0 :         PR_Lock(rwlock->rw_lock);
     262             :         /*
     263             :          * wait if read locked
     264             :          */
     265           0 :         while (rwlock->rw_lock_cnt != 0) {
     266           0 :                 rwlock->rw_writer_cnt++;
     267           0 :                 PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
     268           0 :                 rwlock->rw_writer_cnt--;
     269             :         }
     270             :         /*
     271             :          * apply write lock
     272             :          */
     273           0 :         rwlock->rw_lock_cnt--;
     274           0 :         PR_ASSERT(rwlock->rw_lock_cnt == -1);
     275             : #ifdef DEBUG
     276           0 :         PR_ASSERT(me != NULL);
     277           0 :         rwlock->rw_owner = me;
     278             : #endif
     279           0 :         PR_Unlock(rwlock->rw_lock);
     280             : #endif
     281             : 
     282             : #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
     283             :         /*
     284             :          * update thread's lock rank
     285             :          */
     286           0 :         if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
     287           0 :                 _PR_SET_THREAD_RWLOCK_RANK(rwlock);
     288             : #endif
     289           0 : }
     290             : 
     291             : /*
     292             : ** Unlock the RW lock.
     293             : */
     294             : PR_IMPLEMENT(void)
     295             : PR_RWLock_Unlock(PRRWLock *rwlock)
     296             : {
     297             : #if defined(DEBUG)
     298           0 : PRThread *me = PR_GetCurrentThread();
     299             : #endif
     300             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     301             : int err;
     302             : #endif
     303             : 
     304             : #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
     305             :         err = RWLOCK_UNLOCK(&rwlock->rw_lock);
     306             :         PR_ASSERT(err == 0);
     307             : #else
     308           0 :         PR_Lock(rwlock->rw_lock);
     309             :         /*
     310             :          * lock must be read or write-locked
     311             :          */
     312           0 :         PR_ASSERT(rwlock->rw_lock_cnt != 0);
     313           0 :         if (rwlock->rw_lock_cnt > 0) {
     314             : 
     315             :                 /*
     316             :                  * decrement read-lock count
     317             :                  */
     318           0 :                 rwlock->rw_lock_cnt--;
     319           0 :                 if (rwlock->rw_lock_cnt == 0) {
     320             :                         /*
     321             :                          * lock is not read-locked anymore; wakeup a waiting writer
     322             :                          */
     323           0 :                         if (rwlock->rw_writer_cnt > 0)
     324           0 :                                 PR_NotifyCondVar(rwlock->rw_writer_waitq);
     325             :                 }
     326             :         } else {
     327           0 :                 PR_ASSERT(rwlock->rw_lock_cnt == -1);
     328             : 
     329           0 :                 rwlock->rw_lock_cnt = 0;
     330             : #ifdef DEBUG
     331           0 :         PR_ASSERT(rwlock->rw_owner == me);
     332           0 :         rwlock->rw_owner = NULL;
     333             : #endif
     334             :                 /*
     335             :                  * wakeup a writer, if present; preference for writers
     336             :                  */
     337           0 :                 if (rwlock->rw_writer_cnt > 0)
     338           0 :                         PR_NotifyCondVar(rwlock->rw_writer_waitq);
     339             :                 /*
     340             :                  * else, wakeup all readers, if any
     341             :                  */
     342           0 :                 else if (rwlock->rw_reader_cnt > 0)
     343           0 :                         PR_NotifyAllCondVar(rwlock->rw_reader_waitq);
     344             :         }
     345           0 :         PR_Unlock(rwlock->rw_lock);
     346             : #endif
     347             : 
     348             : #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
     349             :         /*
     350             :          * update thread's lock rank
     351             :          */
     352           0 :         if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
     353           0 :                 _PR_UNSET_THREAD_RWLOCK_RANK(rwlock);
     354             : #endif
     355           0 :         return;
     356             : }
     357             : 
     358             : #ifndef _PR_RWLOCK_RANK_ORDER_DEBUG
     359             : 
     360             : void _PR_InitRWLocks(void) { }
     361             : 
     362             : #else
     363             : 
     364           3 : void _PR_InitRWLocks(void)
     365             : {
     366             :         /*
     367             :          * allocated thread-private-data index for rwlock list
     368             :          */
     369           3 :         if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key,
     370             :                         _PR_RELEASE_LOCK_STACK) == PR_FAILURE) {
     371           0 :                 pr_thread_rwlock_alloc_failed = 1;
     372           0 :                 return;
     373             :         }
     374             : }
     375             : 
     376             : /*
     377             :  * _PR_SET_THREAD_RWLOCK_RANK
     378             :  *              Set a thread's lock rank, which is the highest of the ranks of all
     379             :  *              the locks held by the thread. Pointers to the locks are added to a
     380             :  *              per-thread list, which is anchored off a thread-private data key.
     381             :  */
     382             : 
     383             : static void
     384           0 : _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
     385             : {
     386             : thread_rwlock_stack *lock_stack;
     387             : PRStatus rv;
     388             : 
     389             :         /*
     390             :          * allocate a lock stack
     391             :          */
     392           0 :         if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) {
     393           0 :                 lock_stack = (thread_rwlock_stack *)
     394             :                                                 PR_CALLOC(1 * sizeof(thread_rwlock_stack));
     395           0 :                 if (lock_stack) {
     396           0 :                         rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack);
     397           0 :                         if (rv == PR_FAILURE) {
     398           0 :                                 PR_DELETE(lock_stack);
     399           0 :                                 pr_thread_rwlock_alloc_failed = 1;
     400           0 :                                 return;
     401             :                         }
     402             :                 } else {
     403           0 :                         pr_thread_rwlock_alloc_failed = 1;
     404           0 :                         return;
     405             :                 }
     406             :         }
     407             :         /*
     408             :          * add rwlock to lock stack, if limit is not exceeded
     409             :          */
     410           0 :         if (lock_stack) {
     411           0 :                 if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT)
     412           0 :                         lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;  
     413             :         }
     414             : }
     415             : 
     416             : static void
     417           0 : _PR_RELEASE_LOCK_STACK(void *lock_stack)
     418             : {
     419           0 :         PR_ASSERT(lock_stack);
     420           0 :         PR_DELETE(lock_stack);
     421           0 : }
     422             : 
     423             : /*
     424             :  * _PR_GET_THREAD_RWLOCK_RANK
     425             :  *
     426             :  *              return thread's lock rank. If thread-private-data for the lock
     427             :  *              stack is not allocated, return PR_RWLOCK_RANK_NONE.
     428             :  */
     429             :         
     430             : static PRUint32
     431           0 : _PR_GET_THREAD_RWLOCK_RANK(void)
     432             : {
     433             :         thread_rwlock_stack *lock_stack;
     434             : 
     435           0 :         lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
     436           0 :         if (lock_stack == NULL || lock_stack->trs_index == 0)
     437           0 :                 return (PR_RWLOCK_RANK_NONE);
     438             :         else
     439           0 :                 return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
     440             : }
     441             : 
     442             : /*
     443             :  * _PR_UNSET_THREAD_RWLOCK_RANK
     444             :  *
     445             :  *              remove the rwlock from the lock stack. Since locks may not be
     446             :  *              unlocked in a FIFO order, the entire lock stack is searched.
     447             :  */
     448             :         
     449             : static void
     450           0 : _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
     451             : {
     452             :         thread_rwlock_stack *lock_stack;
     453           0 :         int new_index = 0, index, done = 0;
     454             : 
     455           0 :         lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
     456             : 
     457           0 :         PR_ASSERT(lock_stack != NULL);
     458             : 
     459           0 :         for (index = lock_stack->trs_index - 1; index >= 0; index--) {
     460           0 :                 if (!done && (lock_stack->trs_stack[index] == rwlock))  {
     461             :                         /*
     462             :                          * reset the slot for rwlock
     463             :                          */
     464           0 :                         lock_stack->trs_stack[index] = NULL;
     465           0 :                         done = 1;
     466             :                 }
     467             :                 /*
     468             :                  * search for the lowest-numbered empty slot, above which there are
     469             :                  * no non-empty slots
     470             :                  */
     471           0 :                 if (!new_index && (lock_stack->trs_stack[index] != NULL))
     472           0 :                         new_index = index + 1;
     473           0 :                 if (done && new_index)
     474           0 :                         break;
     475             :         }
     476             :         /*
     477             :          * set top of stack to highest numbered empty slot
     478             :          */
     479           0 :         lock_stack->trs_index = new_index;
     480             : 
     481           0 : }
     482             : 
     483             : #endif  /* _PR_RWLOCK_RANK_ORDER_DEBUG */

Generated by: LCOV version 1.13