LCOV - code coverage report
Current view: top level - nsprpub/pr/src/misc - pratom.c (source / functions) Hit Total Coverage
Test: output.info Lines: 2 44 4.5 %
Date: 2017-07-14 16:53:18 Functions: 1 1 100.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             : /*
       7             : **     PR Atomic operations
       8             : */
       9             : 
      10             : 
      11             : #include "pratom.h"
      12             : #include "primpl.h"
      13             : 
      14             : #include <string.h>
      15             : 
      16             : /*
      17             :  * The following is a fallback implementation that emulates
      18             :  * atomic operations for platforms without atomic operations.
      19             :  * If a platform has atomic operations, it should define the
      20             :  * macro _PR_HAVE_ATOMIC_OPS, and the following will not be
      21             :  * compiled in.
      22             :  */
      23             : 
      24             : #if !defined(_PR_HAVE_ATOMIC_OPS)
      25             : 
      26             : #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
      27             : /*
      28             :  * PR_AtomicDecrement() is used in NSPR's thread-specific data
      29             :  * destructor.  Because thread-specific data destructors may be
      30             :  * invoked after a PR_Cleanup() call, we need an implementation
      31             :  * of the atomic routines that doesn't need NSPR to be initialized.
      32             :  */
      33             : 
      34             : /*
      35             :  * We use a set of locks for all the emulated atomic operations.
      36             :  * By hashing on the address of the integer to be locked the
      37             :  * contention between multiple threads should be lessened.
      38             :  *
      39             :  * The number of atomic locks can be set by the environment variable
      40             :  * NSPR_ATOMIC_HASH_LOCKS
      41             :  */
      42             : 
      43             : /*
      44             :  * lock counts should be a power of 2
      45             :  */
      46             : #define DEFAULT_ATOMIC_LOCKS    16      /* should be in sync with the number of initializers
      47             :                                                                                 below */
      48             : #define MAX_ATOMIC_LOCKS                (4 * 1024)
      49             : 
      50             : static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = {
      51             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      52             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      53             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      54             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      55             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      56             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      57             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      58             :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
      59             : 
      60             : #ifdef DEBUG
      61             : static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS];
      62             : static PRInt32 *hash_lock_counts = static_hash_lock_counts;
      63             : #endif
      64             : 
      65             : static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
      66             : static pthread_mutex_t *atomic_locks = static_atomic_locks;
      67             : static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1;
      68             : 
      69             : #define _PR_HASH_FOR_LOCK(ptr)                                                  \
      70             :                         ((PRUint32) (((PRUptrdiff) (ptr) >> 2)    ^       \
      71             :                                                 ((PRUptrdiff) (ptr) >> 8)) &  \
      72             :                                                 atomic_hash_mask)
      73             : 
      74             : void _PR_MD_INIT_ATOMIC()
      75             : {
      76             : char *eval;
      77             : int index;
      78             : 
      79             : 
      80             :         PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) ==
      81             :                                                 PR_CeilingLog2(MAX_ATOMIC_LOCKS));
      82             : 
      83             :         PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) ==
      84             :                                                         PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS));
      85             : 
      86             :         if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL)  &&
      87             :                 ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) {
      88             : 
      89             :                 if (num_atomic_locks > MAX_ATOMIC_LOCKS)
      90             :                         num_atomic_locks = MAX_ATOMIC_LOCKS;
      91             :                 else if (num_atomic_locks < 1) 
      92             :                         num_atomic_locks = 1;
      93             :                 else {
      94             :                         num_atomic_locks = PR_FloorLog2(num_atomic_locks);
      95             :                         num_atomic_locks = 1L << num_atomic_locks;
      96             :                 }
      97             :                 atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) *
      98             :                                                 num_atomic_locks);
      99             :                 if (atomic_locks) {
     100             :                         for (index = 0; index < num_atomic_locks; index++) {
     101             :                                 if (pthread_mutex_init(&atomic_locks[index], NULL)) {
     102             :                                                 PR_DELETE(atomic_locks);
     103             :                                                 atomic_locks = NULL;
     104             :                                                 break; 
     105             :                                 }
     106             :                         }
     107             :                 }
     108             : #ifdef DEBUG
     109             :                 if (atomic_locks) {
     110             :                         hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32));
     111             :                         if (hash_lock_counts == NULL) {
     112             :                                 PR_DELETE(atomic_locks);
     113             :                                 atomic_locks = NULL;
     114             :                         }
     115             :                 }
     116             : #endif
     117             :                 if (atomic_locks == NULL) {
     118             :                         /*
     119             :                          *      Use statically allocated locks
     120             :                          */
     121             :                         atomic_locks = static_atomic_locks;
     122             :                         num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
     123             :         #ifdef DEBUG
     124             :                         hash_lock_counts = static_hash_lock_counts;
     125             :         #endif
     126             :                 }
     127             :                 atomic_hash_mask = num_atomic_locks - 1;
     128             :         }
     129             :         PR_ASSERT(PR_FloorLog2(num_atomic_locks) ==
     130             :                                                                 PR_CeilingLog2(num_atomic_locks));
     131             : }
     132             : 
     133             : PRInt32
     134             : _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
     135             : {
     136             :     PRInt32 rv;
     137             :     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
     138             : 
     139             :     pthread_mutex_lock(&atomic_locks[idx]);
     140             :     rv = ++(*val);
     141             : #ifdef DEBUG
     142             :     hash_lock_counts[idx]++;
     143             : #endif
     144             :     pthread_mutex_unlock(&atomic_locks[idx]);
     145             :     return rv;
     146             : }
     147             : 
     148             : PRInt32
     149             : _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
     150             : {
     151             :     PRInt32 rv;
     152             :     PRInt32 idx = _PR_HASH_FOR_LOCK(ptr);
     153             : 
     154             :     pthread_mutex_lock(&atomic_locks[idx]);
     155             :     rv = ((*ptr) += val);
     156             : #ifdef DEBUG
     157             :     hash_lock_counts[idx]++;
     158             : #endif
     159             :     pthread_mutex_unlock(&atomic_locks[idx]);
     160             :     return rv;
     161             : }
     162             : 
     163             : PRInt32
     164             : _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
     165             : {
     166             :     PRInt32 rv;
     167             :     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
     168             : 
     169             :     pthread_mutex_lock(&atomic_locks[idx]);
     170             :     rv = --(*val);
     171             : #ifdef DEBUG
     172             :     hash_lock_counts[idx]++;
     173             : #endif
     174             :     pthread_mutex_unlock(&atomic_locks[idx]);
     175             :     return rv;
     176             : }
     177             : 
     178             : PRInt32
     179             : _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
     180             : {
     181             :     PRInt32 rv;
     182             :     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
     183             : 
     184             :     pthread_mutex_lock(&atomic_locks[idx]);
     185             :     rv = *val;
     186             :     *val = newval;
     187             : #ifdef DEBUG
     188             :     hash_lock_counts[idx]++;
     189             : #endif
     190             :     pthread_mutex_unlock(&atomic_locks[idx]);
     191             :     return rv;
     192             : }
     193             : #else  /* _PR_PTHREADS && !_PR_DCETHREADS */
     194             : /*
     195             :  * We use a single lock for all the emulated atomic operations.
     196             :  * The lock contention should be acceptable.
     197             :  */
     198             : static PRLock *atomic_lock = NULL;
     199             : void _PR_MD_INIT_ATOMIC(void)
     200             : {
     201             :     if (atomic_lock == NULL) {
     202             :         atomic_lock = PR_NewLock();
     203             :     }
     204             : }
     205             : 
     206             : PRInt32
     207             : _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
     208             : {
     209             :     PRInt32 rv;
     210             : 
     211             :     if (!_pr_initialized) {
     212             :         _PR_ImplicitInitialization();
     213             :     }
     214             :     PR_Lock(atomic_lock);
     215             :     rv = ++(*val);
     216             :     PR_Unlock(atomic_lock);
     217             :     return rv;
     218             : }
     219             : 
     220             : PRInt32
     221             : _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
     222             : {
     223             :     PRInt32 rv;
     224             : 
     225             :     if (!_pr_initialized) {
     226             :         _PR_ImplicitInitialization();
     227             :     }
     228             :     PR_Lock(atomic_lock);
     229             :     rv = ((*ptr) += val);
     230             :     PR_Unlock(atomic_lock);
     231             :     return rv;
     232             : }
     233             : 
     234             : PRInt32
     235             : _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
     236             : {
     237             :     PRInt32 rv;
     238             : 
     239             :     if (!_pr_initialized) {
     240             :         _PR_ImplicitInitialization();
     241             :     }
     242             :     PR_Lock(atomic_lock);
     243             :     rv = --(*val);
     244             :     PR_Unlock(atomic_lock);
     245             :     return rv;
     246             : }
     247             : 
     248             : PRInt32
     249             : _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
     250             : {
     251             :     PRInt32 rv;
     252             : 
     253             :     if (!_pr_initialized) {
     254             :         _PR_ImplicitInitialization();
     255             :     }
     256             :     PR_Lock(atomic_lock);
     257             :     rv = *val;
     258             :     *val = newval;
     259             :     PR_Unlock(atomic_lock);
     260             :     return rv;
     261             : }
     262             : #endif  /* _PR_PTHREADS && !_PR_DCETHREADS */
     263             : 
     264             : #endif  /* !_PR_HAVE_ATOMIC_OPS */
     265             : 
     266           3 : void _PR_InitAtomic(void)
     267             : {
     268             :     _PR_MD_INIT_ATOMIC();
     269           3 : }
     270             : 
     271             : PR_IMPLEMENT(PRInt32)
     272             : PR_AtomicIncrement(PRInt32 *val)
     273             : {
     274           0 :     return _PR_MD_ATOMIC_INCREMENT(val);
     275             : }
     276             : 
     277             : PR_IMPLEMENT(PRInt32)
     278             : PR_AtomicDecrement(PRInt32 *val)
     279             : {
     280           0 :     return _PR_MD_ATOMIC_DECREMENT(val);
     281             : }
     282             : 
     283             : PR_IMPLEMENT(PRInt32)
     284             : PR_AtomicSet(PRInt32 *val, PRInt32 newval)
     285             : {
     286           0 :     return _PR_MD_ATOMIC_SET(val, newval);
     287             : }
     288             : 
     289             : PR_IMPLEMENT(PRInt32)
     290             : PR_AtomicAdd(PRInt32 *ptr, PRInt32 val)
     291             : {
     292           0 :     return _PR_MD_ATOMIC_ADD(ptr, val);
     293             : }
     294             : /*
     295             :  * For platforms, which don't support the CAS (compare-and-swap) instruction
     296             :  * (or an equivalent), the stack operations are implemented by use of PRLock
     297             :  */
     298             : 
     299             : PR_IMPLEMENT(PRStack *)
     300             : PR_CreateStack(const char *stack_name)
     301             : {
     302             : PRStack *stack;
     303             : 
     304           0 :     if (!_pr_initialized) {
     305           0 :         _PR_ImplicitInitialization();
     306             :     }
     307             : 
     308           0 :     if ((stack = PR_NEW(PRStack)) == NULL) {
     309           0 :                 return NULL;
     310             :         }
     311           0 :         if (stack_name) {
     312           0 :                 stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1);
     313           0 :                 if (stack->prstk_name == NULL) {
     314           0 :                         PR_DELETE(stack);
     315           0 :                         return NULL;
     316             :                 }
     317           0 :                 strcpy(stack->prstk_name, stack_name);
     318             :         } else
     319           0 :                 stack->prstk_name = NULL;
     320             : 
     321             : #ifndef _PR_HAVE_ATOMIC_CAS
     322           0 :     stack->prstk_lock = PR_NewLock();
     323           0 :         if (stack->prstk_lock == NULL) {
     324           0 :                 PR_Free(stack->prstk_name);
     325           0 :                 PR_DELETE(stack);
     326           0 :                 return NULL;
     327             :         }
     328             : #endif /* !_PR_HAVE_ATOMIC_CAS */
     329             : 
     330           0 :         stack->prstk_head.prstk_elem_next = NULL;
     331             :         
     332           0 :     return stack;
     333             : }
     334             : 
     335             : PR_IMPLEMENT(PRStatus)
     336             : PR_DestroyStack(PRStack *stack)
     337             : {
     338           0 :         if (stack->prstk_head.prstk_elem_next != NULL) {
     339           0 :                 PR_SetError(PR_INVALID_STATE_ERROR, 0);
     340           0 :                 return PR_FAILURE;
     341             :         }
     342             : 
     343           0 :         if (stack->prstk_name)
     344           0 :                 PR_Free(stack->prstk_name);
     345             : #ifndef _PR_HAVE_ATOMIC_CAS
     346           0 :         PR_DestroyLock(stack->prstk_lock);
     347             : #endif /* !_PR_HAVE_ATOMIC_CAS */
     348           0 :         PR_DELETE(stack);
     349             : 
     350           0 :         return PR_SUCCESS;
     351             : }
     352             : 
     353             : #ifndef _PR_HAVE_ATOMIC_CAS
     354             : 
     355             : PR_IMPLEMENT(void)
     356             : PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
     357             : {
     358           0 :     PR_Lock(stack->prstk_lock);
     359           0 :         stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next;
     360           0 :         stack->prstk_head.prstk_elem_next = stack_elem;
     361           0 :     PR_Unlock(stack->prstk_lock);
     362           0 :     return;
     363             : }
     364             : 
     365             : PR_IMPLEMENT(PRStackElem *)
     366             : PR_StackPop(PRStack *stack)
     367             : {
     368             : PRStackElem *element;
     369             : 
     370           0 :     PR_Lock(stack->prstk_lock);
     371           0 :         element = stack->prstk_head.prstk_elem_next;
     372           0 :         if (element != NULL) {
     373           0 :                 stack->prstk_head.prstk_elem_next = element->prstk_elem_next;
     374           0 :                 element->prstk_elem_next = NULL;     /* debugging aid */
     375             :         }
     376           0 :     PR_Unlock(stack->prstk_lock);
     377           0 :     return element;
     378             : }
     379             : #endif /* !_PR_HAVE_ATOMIC_CAS */

Generated by: LCOV version 1.13