LCOV - code coverage report
Current view: directory - nsprpub/pr/src/misc - pratom.c (source / functions) Found Hit Coverage
Test: app.info Lines: 51 30 58.8 %
Date: 2012-06-02 Functions: 9 6 66.7 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2000
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : /*
      39                 : **     PR Atomic operations
      40                 : */
      41                 : 
      42                 : 
      43                 : #include "pratom.h"
      44                 : #include "primpl.h"
      45                 : 
      46                 : #include <string.h>
      47                 : 
      48                 : /*
      49                 :  * The following is a fallback implementation that emulates
      50                 :  * atomic operations for platforms without atomic operations.
      51                 :  * If a platform has atomic operations, it should define the
      52                 :  * macro _PR_HAVE_ATOMIC_OPS, and the following will not be
      53                 :  * compiled in.
      54                 :  */
      55                 : 
      56                 : #if !defined(_PR_HAVE_ATOMIC_OPS)
      57                 : 
      58                 : #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
      59                 : /*
      60                 :  * PR_AtomicDecrement() is used in NSPR's thread-specific data
      61                 :  * destructor.  Because thread-specific data destructors may be
      62                 :  * invoked after a PR_Cleanup() call, we need an implementation
      63                 :  * of the atomic routines that doesn't need NSPR to be initialized.
      64                 :  */
      65                 : 
      66                 : /*
      67                 :  * We use a set of locks for all the emulated atomic operations.
      68                 :  * By hashing on the address of the integer to be locked the
      69                 :  * contention between multiple threads should be lessened.
      70                 :  *
      71                 :  * The number of atomic locks can be set by the environment variable
      72                 :  * NSPR_ATOMIC_HASH_LOCKS
      73                 :  */
      74                 : 
      75                 : /*
      76                 :  * lock counts should be a power of 2
      77                 :  */
      78                 : #define DEFAULT_ATOMIC_LOCKS    16      /* should be in sync with the number of initializers
      79                 :                                                                                 below */
      80                 : #define MAX_ATOMIC_LOCKS                (4 * 1024)
      81                 : 
      82                 : static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = {
      83                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      84                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      85                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      86                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      87                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      88                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      89                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
      90                 :         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
      91                 : 
      92                 : #ifdef DEBUG
      93                 : static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS];
      94                 : static PRInt32 *hash_lock_counts = static_hash_lock_counts;
      95                 : #endif
      96                 : 
      97                 : static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
      98                 : static pthread_mutex_t *atomic_locks = static_atomic_locks;
      99                 : static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1;
     100                 : 
     101                 : #define _PR_HASH_FOR_LOCK(ptr)                                                  \
     102                 :                         ((PRUint32) (((PRUptrdiff) (ptr) >> 2)    ^       \
     103                 :                                                 ((PRUptrdiff) (ptr) >> 8)) &  \
     104                 :                                                 atomic_hash_mask)
     105                 : 
     106                 : void _PR_MD_INIT_ATOMIC()
     107                 : {
     108                 : char *eval;
     109                 : int index;
     110                 : 
     111                 : 
     112                 :         PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) ==
     113                 :                                                 PR_CeilingLog2(MAX_ATOMIC_LOCKS));
     114                 : 
     115                 :         PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) ==
     116                 :                                                         PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS));
     117                 : 
     118                 :         if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL)  &&
     119                 :                 ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) {
     120                 : 
     121                 :                 if (num_atomic_locks > MAX_ATOMIC_LOCKS)
     122                 :                         num_atomic_locks = MAX_ATOMIC_LOCKS;
     123                 :                 else if (num_atomic_locks < 1) 
     124                 :                         num_atomic_locks = 1;
     125                 :                 else {
     126                 :                         num_atomic_locks = PR_FloorLog2(num_atomic_locks);
     127                 :                         num_atomic_locks = 1L << num_atomic_locks;
     128                 :                 }
     129                 :                 atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) *
     130                 :                                                 num_atomic_locks);
     131                 :                 if (atomic_locks) {
     132                 :                         for (index = 0; index < num_atomic_locks; index++) {
     133                 :                                 if (pthread_mutex_init(&atomic_locks[index], NULL)) {
     134                 :                                                 PR_DELETE(atomic_locks);
     135                 :                                                 atomic_locks = NULL;
     136                 :                                                 break; 
     137                 :                                 }
     138                 :                         }
     139                 :                 }
     140                 : #ifdef DEBUG
     141                 :                 if (atomic_locks) {
     142                 :                         hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32));
     143                 :                         if (hash_lock_counts == NULL) {
     144                 :                                 PR_DELETE(atomic_locks);
     145                 :                                 atomic_locks = NULL;
     146                 :                         }
     147                 :                 }
     148                 : #endif
     149                 :                 if (atomic_locks == NULL) {
     150                 :                         /*
     151                 :                          *      Use statically allocated locks
     152                 :                          */
     153                 :                         atomic_locks = static_atomic_locks;
     154                 :                         num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
     155                 :         #ifdef DEBUG
     156                 :                         hash_lock_counts = static_hash_lock_counts;
     157                 :         #endif
     158                 :                 }
     159                 :                 atomic_hash_mask = num_atomic_locks - 1;
     160                 :         }
     161                 :         PR_ASSERT(PR_FloorLog2(num_atomic_locks) ==
     162                 :                                                                 PR_CeilingLog2(num_atomic_locks));
     163                 : }
     164                 : 
     165                 : PRInt32
     166                 : _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
     167                 : {
     168                 :     PRInt32 rv;
     169                 :     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
     170                 : 
     171                 :     pthread_mutex_lock(&atomic_locks[idx]);
     172                 :     rv = ++(*val);
     173                 : #ifdef DEBUG
     174                 :     hash_lock_counts[idx]++;
     175                 : #endif
     176                 :     pthread_mutex_unlock(&atomic_locks[idx]);
     177                 :     return rv;
     178                 : }
     179                 : 
     180                 : PRInt32
     181                 : _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
     182                 : {
     183                 :     PRInt32 rv;
     184                 :     PRInt32 idx = _PR_HASH_FOR_LOCK(ptr);
     185                 : 
     186                 :     pthread_mutex_lock(&atomic_locks[idx]);
     187                 :     rv = ((*ptr) += val);
     188                 : #ifdef DEBUG
     189                 :     hash_lock_counts[idx]++;
     190                 : #endif
     191                 :     pthread_mutex_unlock(&atomic_locks[idx]);
     192                 :     return rv;
     193                 : }
     194                 : 
     195                 : PRInt32
     196                 : _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
     197                 : {
     198                 :     PRInt32 rv;
     199                 :     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
     200                 : 
     201                 :     pthread_mutex_lock(&atomic_locks[idx]);
     202                 :     rv = --(*val);
     203                 : #ifdef DEBUG
     204                 :     hash_lock_counts[idx]++;
     205                 : #endif
     206                 :     pthread_mutex_unlock(&atomic_locks[idx]);
     207                 :     return rv;
     208                 : }
     209                 : 
     210                 : PRInt32
     211                 : _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
     212                 : {
     213                 :     PRInt32 rv;
     214                 :     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
     215                 : 
     216                 :     pthread_mutex_lock(&atomic_locks[idx]);
     217                 :     rv = *val;
     218                 :     *val = newval;
     219                 : #ifdef DEBUG
     220                 :     hash_lock_counts[idx]++;
     221                 : #endif
     222                 :     pthread_mutex_unlock(&atomic_locks[idx]);
     223                 :     return rv;
     224                 : }
     225                 : #else  /* _PR_PTHREADS && !_PR_DCETHREADS */
     226                 : /*
     227                 :  * We use a single lock for all the emulated atomic operations.
     228                 :  * The lock contention should be acceptable.
     229                 :  */
     230                 : static PRLock *atomic_lock = NULL;
     231                 : void _PR_MD_INIT_ATOMIC(void)
     232                 : {
     233                 :     if (atomic_lock == NULL) {
     234                 :         atomic_lock = PR_NewLock();
     235                 :     }
     236                 : }
     237                 : 
     238                 : PRInt32
     239                 : _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
     240                 : {
     241                 :     PRInt32 rv;
     242                 : 
     243                 :     if (!_pr_initialized) {
     244                 :         _PR_ImplicitInitialization();
     245                 :     }
     246                 :     PR_Lock(atomic_lock);
     247                 :     rv = ++(*val);
     248                 :     PR_Unlock(atomic_lock);
     249                 :     return rv;
     250                 : }
     251                 : 
     252                 : PRInt32
     253                 : _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
     254                 : {
     255                 :     PRInt32 rv;
     256                 : 
     257                 :     if (!_pr_initialized) {
     258                 :         _PR_ImplicitInitialization();
     259                 :     }
     260                 :     PR_Lock(atomic_lock);
     261                 :     rv = ((*ptr) += val);
     262                 :     PR_Unlock(atomic_lock);
     263                 :     return rv;
     264                 : }
     265                 : 
     266                 : PRInt32
     267                 : _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
     268                 : {
     269                 :     PRInt32 rv;
     270                 : 
     271                 :     if (!_pr_initialized) {
     272                 :         _PR_ImplicitInitialization();
     273                 :     }
     274                 :     PR_Lock(atomic_lock);
     275                 :     rv = --(*val);
     276                 :     PR_Unlock(atomic_lock);
     277                 :     return rv;
     278                 : }
     279                 : 
     280                 : PRInt32
     281                 : _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
     282                 : {
     283                 :     PRInt32 rv;
     284                 : 
     285                 :     if (!_pr_initialized) {
     286                 :         _PR_ImplicitInitialization();
     287                 :     }
     288                 :     PR_Lock(atomic_lock);
     289                 :     rv = *val;
     290                 :     *val = newval;
     291                 :     PR_Unlock(atomic_lock);
     292                 :     return rv;
     293                 : }
     294                 : #endif  /* _PR_PTHREADS && !_PR_DCETHREADS */
     295                 : 
     296                 : #endif  /* !_PR_HAVE_ATOMIC_OPS */
     297                 : 
     298           20034 : void _PR_InitAtomic(void)
     299                 : {
     300                 :     _PR_MD_INIT_ATOMIC();
     301           20034 : }
     302                 : 
     303                 : PR_IMPLEMENT(PRInt32)
     304               0 : PR_AtomicIncrement(PRInt32 *val)
     305                 : {
     306               0 :     return _PR_MD_ATOMIC_INCREMENT(val);
     307                 : }
     308                 : 
     309                 : PR_IMPLEMENT(PRInt32)
     310               0 : PR_AtomicDecrement(PRInt32 *val)
     311                 : {
     312               0 :     return _PR_MD_ATOMIC_DECREMENT(val);
     313                 : }
     314                 : 
     315                 : PR_IMPLEMENT(PRInt32)
     316             984 : PR_AtomicSet(PRInt32 *val, PRInt32 newval)
     317                 : {
     318             984 :     return _PR_MD_ATOMIC_SET(val, newval);
     319                 : }
     320                 : 
     321                 : PR_IMPLEMENT(PRInt32)
     322            8552 : PR_AtomicAdd(PRInt32 *ptr, PRInt32 val)
     323                 : {
     324            8552 :     return _PR_MD_ATOMIC_ADD(ptr, val);
     325                 : }
     326                 : /*
     327                 :  * For platforms, which don't support the CAS (compare-and-swap) instruction
     328                 :  * (or an equivalent), the stack operations are implemented by use of PRLock
     329                 :  */
     330                 : 
     331                 : PR_IMPLEMENT(PRStack *)
     332           20034 : PR_CreateStack(const char *stack_name)
     333                 : {
     334                 : PRStack *stack;
     335                 : 
     336           20034 :     if (!_pr_initialized) {
     337               0 :         _PR_ImplicitInitialization();
     338                 :     }
     339                 : 
     340           20034 :     if ((stack = PR_NEW(PRStack)) == NULL) {
     341               0 :                 return NULL;
     342                 :         }
     343           20034 :         if (stack_name) {
     344           20034 :                 stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1);
     345           20034 :                 if (stack->prstk_name == NULL) {
     346               0 :                         PR_DELETE(stack);
     347               0 :                         return NULL;
     348                 :                 }
     349           20034 :                 strcpy(stack->prstk_name, stack_name);
     350                 :         } else
     351               0 :                 stack->prstk_name = NULL;
     352                 : 
     353                 : #ifndef _PR_HAVE_ATOMIC_CAS
     354           20034 :     stack->prstk_lock = PR_NewLock();
     355           20034 :         if (stack->prstk_lock == NULL) {
     356               0 :                 PR_Free(stack->prstk_name);
     357               0 :                 PR_DELETE(stack);
     358               0 :                 return NULL;
     359                 :         }
     360                 : #endif /* !_PR_HAVE_ATOMIC_CAS */
     361                 : 
     362           20034 :         stack->prstk_head.prstk_elem_next = NULL;
     363                 :         
     364           20034 :     return stack;
     365                 : }
     366                 : 
     367                 : PR_IMPLEMENT(PRStatus)
     368             140 : PR_DestroyStack(PRStack *stack)
     369                 : {
     370             140 :         if (stack->prstk_head.prstk_elem_next != NULL) {
     371               0 :                 PR_SetError(PR_INVALID_STATE_ERROR, 0);
     372               0 :                 return PR_FAILURE;
     373                 :         }
     374                 : 
     375             140 :         if (stack->prstk_name)
     376             140 :                 PR_Free(stack->prstk_name);
     377                 : #ifndef _PR_HAVE_ATOMIC_CAS
     378             140 :         PR_DestroyLock(stack->prstk_lock);
     379                 : #endif /* !_PR_HAVE_ATOMIC_CAS */
     380             140 :         PR_DELETE(stack);
     381                 : 
     382             140 :         return PR_SUCCESS;
     383                 : }
     384                 : 
     385                 : #ifndef _PR_HAVE_ATOMIC_CAS
     386                 : 
     387                 : PR_IMPLEMENT(void)
     388               0 : PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
     389                 : {
     390               0 :     PR_Lock(stack->prstk_lock);
     391               0 :         stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next;
     392               0 :         stack->prstk_head.prstk_elem_next = stack_elem;
     393               0 :     PR_Unlock(stack->prstk_lock);
     394                 :     return;
     395                 : }
     396                 : 
     397                 : PR_IMPLEMENT(PRStackElem *)
     398             140 : PR_StackPop(PRStack *stack)
     399                 : {
     400                 : PRStackElem *element;
     401                 : 
     402             140 :     PR_Lock(stack->prstk_lock);
     403             140 :         element = stack->prstk_head.prstk_elem_next;
     404             140 :         if (element != NULL) {
     405               0 :                 stack->prstk_head.prstk_elem_next = element->prstk_elem_next;
     406               0 :                 element->prstk_elem_next = NULL;     /* debugging aid */
     407                 :         }
     408             140 :     PR_Unlock(stack->prstk_lock);
     409             140 :     return element;
     410                 : }
     411                 : #endif /* !_PR_HAVE_ATOMIC_CAS */

Generated by: LCOV version 1.7