nsprpub/pr/src/misc/pratom.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 /*
     7 **     PR Atomic operations
     8 */
    11 #include "pratom.h"
    12 #include "primpl.h"
    14 #include <string.h>
    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  */
    24 #if !defined(_PR_HAVE_ATOMIC_OPS)
    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  */
    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  */
    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)
    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 };
    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
    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;
    69 #define _PR_HASH_FOR_LOCK(ptr) 							\
    70 			((PRUint32) (((PRUptrdiff) (ptr) >> 2)	^	\
    71 						((PRUptrdiff) (ptr) >> 8)) &	\
    72 						atomic_hash_mask)
    74 void _PR_MD_INIT_ATOMIC()
    75 {
    76 char *eval;
    77 int index;
    80 	PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) ==
    81 						PR_CeilingLog2(MAX_ATOMIC_LOCKS));
    83 	PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) ==
    84 							PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS));
    86 	if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL)  &&
    87 		((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) {
    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 }
   133 PRInt32
   134 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
   135 {
   136     PRInt32 rv;
   137     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
   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 }
   148 PRInt32
   149 _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
   150 {
   151     PRInt32 rv;
   152     PRInt32 idx = _PR_HASH_FOR_LOCK(ptr);
   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 }
   163 PRInt32
   164 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
   165 {
   166     PRInt32 rv;
   167     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
   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 }
   178 PRInt32
   179 _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
   180 {
   181     PRInt32 rv;
   182     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
   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 }
   206 PRInt32
   207 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
   208 {
   209     PRInt32 rv;
   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 }
   220 PRInt32
   221 _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
   222 {
   223     PRInt32 rv;
   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 }
   234 PRInt32
   235 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
   236 {
   237     PRInt32 rv;
   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 }
   248 PRInt32
   249 _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
   250 {
   251     PRInt32 rv;
   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 */
   264 #endif  /* !_PR_HAVE_ATOMIC_OPS */
   266 void _PR_InitAtomic(void)
   267 {
   268     _PR_MD_INIT_ATOMIC();
   269 }
   271 PR_IMPLEMENT(PRInt32)
   272 PR_AtomicIncrement(PRInt32 *val)
   273 {
   274     return _PR_MD_ATOMIC_INCREMENT(val);
   275 }
   277 PR_IMPLEMENT(PRInt32)
   278 PR_AtomicDecrement(PRInt32 *val)
   279 {
   280     return _PR_MD_ATOMIC_DECREMENT(val);
   281 }
   283 PR_IMPLEMENT(PRInt32)
   284 PR_AtomicSet(PRInt32 *val, PRInt32 newval)
   285 {
   286     return _PR_MD_ATOMIC_SET(val, newval);
   287 }
   289 PR_IMPLEMENT(PRInt32)
   290 PR_AtomicAdd(PRInt32 *ptr, PRInt32 val)
   291 {
   292     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  */
   299 PR_IMPLEMENT(PRStack *)
   300 PR_CreateStack(const char *stack_name)
   301 {
   302 PRStack *stack;
   304     if (!_pr_initialized) {
   305         _PR_ImplicitInitialization();
   306     }
   308     if ((stack = PR_NEW(PRStack)) == NULL) {
   309 		return NULL;
   310 	}
   311 	if (stack_name) {
   312 		stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1);
   313 		if (stack->prstk_name == NULL) {
   314 			PR_DELETE(stack);
   315 			return NULL;
   316 		}
   317 		strcpy(stack->prstk_name, stack_name);
   318 	} else
   319 		stack->prstk_name = NULL;
   321 #ifndef _PR_HAVE_ATOMIC_CAS
   322     stack->prstk_lock = PR_NewLock();
   323 	if (stack->prstk_lock == NULL) {
   324 		PR_Free(stack->prstk_name);
   325 		PR_DELETE(stack);
   326 		return NULL;
   327 	}
   328 #endif /* !_PR_HAVE_ATOMIC_CAS */
   330 	stack->prstk_head.prstk_elem_next = NULL;
   332     return stack;
   333 }
   335 PR_IMPLEMENT(PRStatus)
   336 PR_DestroyStack(PRStack *stack)
   337 {
   338 	if (stack->prstk_head.prstk_elem_next != NULL) {
   339 		PR_SetError(PR_INVALID_STATE_ERROR, 0);
   340 		return PR_FAILURE;
   341 	}
   343 	if (stack->prstk_name)
   344 		PR_Free(stack->prstk_name);
   345 #ifndef _PR_HAVE_ATOMIC_CAS
   346 	PR_DestroyLock(stack->prstk_lock);
   347 #endif /* !_PR_HAVE_ATOMIC_CAS */
   348 	PR_DELETE(stack);
   350 	return PR_SUCCESS;
   351 }
   353 #ifndef _PR_HAVE_ATOMIC_CAS
   355 PR_IMPLEMENT(void)
   356 PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
   357 {
   358     PR_Lock(stack->prstk_lock);
   359 	stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next;
   360 	stack->prstk_head.prstk_elem_next = stack_elem;
   361     PR_Unlock(stack->prstk_lock);
   362     return;
   363 }
   365 PR_IMPLEMENT(PRStackElem *)
   366 PR_StackPop(PRStack *stack)
   367 {
   368 PRStackElem *element;
   370     PR_Lock(stack->prstk_lock);
   371 	element = stack->prstk_head.prstk_elem_next;
   372 	if (element != NULL) {
   373 		stack->prstk_head.prstk_elem_next = element->prstk_elem_next;
   374 		element->prstk_elem_next = NULL;	/* debugging aid */
   375 	}
   376     PR_Unlock(stack->prstk_lock);
   377     return element;
   378 }
   379 #endif /* !_PR_HAVE_ATOMIC_CAS */

mercurial