LCOV - app.info - nsprpub/pr/src/misc/pratom.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/misc - pratom.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 51 | 13 | 25.5 %
| Date: | 2012-04-07 | Functions: | 9 | 2 | 22.2 %

           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           18667 : void _PR_InitAtomic(void)
         299                 : {
         300                 :     _PR_MD_INIT_ATOMIC();
         301           18667 : }
         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               0 : PR_AtomicSet(PRInt32 *val, PRInt32 newval)
         317                 : {
         318               0 :     return _PR_MD_ATOMIC_SET(val, newval);
         319                 : }
         320                 :
         321                 : PR_IMPLEMENT(PRInt32)
         322               0 : PR_AtomicAdd(PRInt32 *ptr, PRInt32 val)
         323                 : {
         324               0 :     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           18667 : PR_CreateStack(const char *stack_name)
         333                 : {
         334                 : PRStack *stack;
         335                 :
         336           18667 :     if (!_pr_initialized) {
         337               0 :         _PR_ImplicitInitialization();
         338                 :     }
         339                 :
         340           18667 :     if ((stack = PR_NEW(PRStack)) == NULL) {
         341               0 :                 return NULL;
         342                 :         }
         343           18667 :         if (stack_name) {
         344           18667 :                 stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1);
         345           18667 :                 if (stack->prstk_name == NULL) {
         346               0 :                         PR_DELETE(stack);
         347               0 :                         return NULL;
         348                 :                 }
         349           18667 :                 strcpy(stack->prstk_name, stack_name);
         350                 :         } else
         351               0 :                 stack->prstk_name = NULL;
         352                 :
         353                 : #ifndef _PR_HAVE_ATOMIC_CAS
         354           18667 :     stack->prstk_lock = PR_NewLock();
         355           18667 :         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           18667 :         stack->prstk_head.prstk_elem_next = NULL;
         363                 :
         364           18667 :     return stack;
         365                 : }
         366                 :
         367                 : PR_IMPLEMENT(PRStatus)
         368               0 : PR_DestroyStack(PRStack *stack)
         369                 : {
         370               0 :         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               0 :         if (stack->prstk_name)
         376               0 :                 PR_Free(stack->prstk_name);
         377                 : #ifndef _PR_HAVE_ATOMIC_CAS
         378               0 :         PR_DestroyLock(stack->prstk_lock);
         379                 : #endif /* !_PR_HAVE_ATOMIC_CAS */
         380               0 :         PR_DELETE(stack);
         381                 :
         382               0 :         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               0 : PR_StackPop(PRStack *stack)
         399                 : {
         400                 : PRStackElem *element;
         401                 :
         402               0 :     PR_Lock(stack->prstk_lock);
         403               0 :         element = stack->prstk_head.prstk_elem_next;
         404               0 :         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               0 :     PR_Unlock(stack->prstk_lock);
         409               0 :     return element;
         410                 : }
         411                 : #endif /* !_PR_HAVE_ATOMIC_CAS */

Generated by: LCOV version 1.7