Index: mozilla/nsprpub/pr/src/misc/pratom.c |
=================================================================== |
--- mozilla/nsprpub/pr/src/misc/pratom.c (revision 191424) |
+++ mozilla/nsprpub/pr/src/misc/pratom.c (working copy) |
@@ -1,379 +0,0 @@ |
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
- |
-/* |
-** PR Atomic operations |
-*/ |
- |
- |
-#include "pratom.h" |
-#include "primpl.h" |
- |
-#include <string.h> |
- |
-/* |
- * The following is a fallback implementation that emulates |
- * atomic operations for platforms without atomic operations. |
- * If a platform has atomic operations, it should define the |
- * macro _PR_HAVE_ATOMIC_OPS, and the following will not be |
- * compiled in. |
- */ |
- |
-#if !defined(_PR_HAVE_ATOMIC_OPS) |
- |
-#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) |
-/* |
- * PR_AtomicDecrement() is used in NSPR's thread-specific data |
- * destructor. Because thread-specific data destructors may be |
- * invoked after a PR_Cleanup() call, we need an implementation |
- * of the atomic routines that doesn't need NSPR to be initialized. |
- */ |
- |
-/* |
- * We use a set of locks for all the emulated atomic operations. |
- * By hashing on the address of the integer to be locked the |
- * contention between multiple threads should be lessened. |
- * |
- * The number of atomic locks can be set by the environment variable |
- * NSPR_ATOMIC_HASH_LOCKS |
- */ |
- |
-/* |
- * lock counts should be a power of 2 |
- */ |
-#define DEFAULT_ATOMIC_LOCKS 16 /* should be in sync with the number of initializers |
- below */ |
-#define MAX_ATOMIC_LOCKS (4 * 1024) |
- |
-static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = { |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, |
- PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; |
- |
-#ifdef DEBUG |
-static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS]; |
-static PRInt32 *hash_lock_counts = static_hash_lock_counts; |
-#endif |
- |
-static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS; |
-static pthread_mutex_t *atomic_locks = static_atomic_locks; |
-static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1; |
- |
-#define _PR_HASH_FOR_LOCK(ptr) \ |
- ((PRUint32) (((PRUptrdiff) (ptr) >> 2) ^ \ |
- ((PRUptrdiff) (ptr) >> 8)) & \ |
- atomic_hash_mask) |
- |
-void _PR_MD_INIT_ATOMIC() |
-{ |
-char *eval; |
-int index; |
- |
- |
- PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) == |
- PR_CeilingLog2(MAX_ATOMIC_LOCKS)); |
- |
- PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) == |
- PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS)); |
- |
- if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL) && |
- ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) { |
- |
- if (num_atomic_locks > MAX_ATOMIC_LOCKS) |
- num_atomic_locks = MAX_ATOMIC_LOCKS; |
- else if (num_atomic_locks < 1) |
- num_atomic_locks = 1; |
- else { |
- num_atomic_locks = PR_FloorLog2(num_atomic_locks); |
- num_atomic_locks = 1L << num_atomic_locks; |
- } |
- atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) * |
- num_atomic_locks); |
- if (atomic_locks) { |
- for (index = 0; index < num_atomic_locks; index++) { |
- if (pthread_mutex_init(&atomic_locks[index], NULL)) { |
- PR_DELETE(atomic_locks); |
- atomic_locks = NULL; |
- break; |
- } |
- } |
- } |
-#ifdef DEBUG |
- if (atomic_locks) { |
- hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32)); |
- if (hash_lock_counts == NULL) { |
- PR_DELETE(atomic_locks); |
- atomic_locks = NULL; |
- } |
- } |
-#endif |
- if (atomic_locks == NULL) { |
- /* |
- * Use statically allocated locks |
- */ |
- atomic_locks = static_atomic_locks; |
- num_atomic_locks = DEFAULT_ATOMIC_LOCKS; |
- #ifdef DEBUG |
- hash_lock_counts = static_hash_lock_counts; |
- #endif |
- } |
- atomic_hash_mask = num_atomic_locks - 1; |
- } |
- PR_ASSERT(PR_FloorLog2(num_atomic_locks) == |
- PR_CeilingLog2(num_atomic_locks)); |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_INCREMENT(PRInt32 *val) |
-{ |
- PRInt32 rv; |
- PRInt32 idx = _PR_HASH_FOR_LOCK(val); |
- |
- pthread_mutex_lock(&atomic_locks[idx]); |
- rv = ++(*val); |
-#ifdef DEBUG |
- hash_lock_counts[idx]++; |
-#endif |
- pthread_mutex_unlock(&atomic_locks[idx]); |
- return rv; |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) |
-{ |
- PRInt32 rv; |
- PRInt32 idx = _PR_HASH_FOR_LOCK(ptr); |
- |
- pthread_mutex_lock(&atomic_locks[idx]); |
- rv = ((*ptr) += val); |
-#ifdef DEBUG |
- hash_lock_counts[idx]++; |
-#endif |
- pthread_mutex_unlock(&atomic_locks[idx]); |
- return rv; |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_DECREMENT(PRInt32 *val) |
-{ |
- PRInt32 rv; |
- PRInt32 idx = _PR_HASH_FOR_LOCK(val); |
- |
- pthread_mutex_lock(&atomic_locks[idx]); |
- rv = --(*val); |
-#ifdef DEBUG |
- hash_lock_counts[idx]++; |
-#endif |
- pthread_mutex_unlock(&atomic_locks[idx]); |
- return rv; |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) |
-{ |
- PRInt32 rv; |
- PRInt32 idx = _PR_HASH_FOR_LOCK(val); |
- |
- pthread_mutex_lock(&atomic_locks[idx]); |
- rv = *val; |
- *val = newval; |
-#ifdef DEBUG |
- hash_lock_counts[idx]++; |
-#endif |
- pthread_mutex_unlock(&atomic_locks[idx]); |
- return rv; |
-} |
-#else /* _PR_PTHREADS && !_PR_DCETHREADS */ |
-/* |
- * We use a single lock for all the emulated atomic operations. |
- * The lock contention should be acceptable. |
- */ |
-static PRLock *atomic_lock = NULL; |
-void _PR_MD_INIT_ATOMIC(void) |
-{ |
- if (atomic_lock == NULL) { |
- atomic_lock = PR_NewLock(); |
- } |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_INCREMENT(PRInt32 *val) |
-{ |
- PRInt32 rv; |
- |
- if (!_pr_initialized) { |
- _PR_ImplicitInitialization(); |
- } |
- PR_Lock(atomic_lock); |
- rv = ++(*val); |
- PR_Unlock(atomic_lock); |
- return rv; |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) |
-{ |
- PRInt32 rv; |
- |
- if (!_pr_initialized) { |
- _PR_ImplicitInitialization(); |
- } |
- PR_Lock(atomic_lock); |
- rv = ((*ptr) += val); |
- PR_Unlock(atomic_lock); |
- return rv; |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_DECREMENT(PRInt32 *val) |
-{ |
- PRInt32 rv; |
- |
- if (!_pr_initialized) { |
- _PR_ImplicitInitialization(); |
- } |
- PR_Lock(atomic_lock); |
- rv = --(*val); |
- PR_Unlock(atomic_lock); |
- return rv; |
-} |
- |
-PRInt32 |
-_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) |
-{ |
- PRInt32 rv; |
- |
- if (!_pr_initialized) { |
- _PR_ImplicitInitialization(); |
- } |
- PR_Lock(atomic_lock); |
- rv = *val; |
- *val = newval; |
- PR_Unlock(atomic_lock); |
- return rv; |
-} |
-#endif /* _PR_PTHREADS && !_PR_DCETHREADS */ |
- |
-#endif /* !_PR_HAVE_ATOMIC_OPS */ |
- |
-void _PR_InitAtomic(void) |
-{ |
- _PR_MD_INIT_ATOMIC(); |
-} |
- |
-PR_IMPLEMENT(PRInt32) |
-PR_AtomicIncrement(PRInt32 *val) |
-{ |
- return _PR_MD_ATOMIC_INCREMENT(val); |
-} |
- |
-PR_IMPLEMENT(PRInt32) |
-PR_AtomicDecrement(PRInt32 *val) |
-{ |
- return _PR_MD_ATOMIC_DECREMENT(val); |
-} |
- |
-PR_IMPLEMENT(PRInt32) |
-PR_AtomicSet(PRInt32 *val, PRInt32 newval) |
-{ |
- return _PR_MD_ATOMIC_SET(val, newval); |
-} |
- |
-PR_IMPLEMENT(PRInt32) |
-PR_AtomicAdd(PRInt32 *ptr, PRInt32 val) |
-{ |
- return _PR_MD_ATOMIC_ADD(ptr, val); |
-} |
-/* |
- * For platforms, which don't support the CAS (compare-and-swap) instruction |
- * (or an equivalent), the stack operations are implemented by use of PRLock |
- */ |
- |
-PR_IMPLEMENT(PRStack *) |
-PR_CreateStack(const char *stack_name) |
-{ |
-PRStack *stack; |
- |
- if (!_pr_initialized) { |
- _PR_ImplicitInitialization(); |
- } |
- |
- if ((stack = PR_NEW(PRStack)) == NULL) { |
- return NULL; |
- } |
- if (stack_name) { |
- stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1); |
- if (stack->prstk_name == NULL) { |
- PR_DELETE(stack); |
- return NULL; |
- } |
- strcpy(stack->prstk_name, stack_name); |
- } else |
- stack->prstk_name = NULL; |
- |
-#ifndef _PR_HAVE_ATOMIC_CAS |
- stack->prstk_lock = PR_NewLock(); |
- if (stack->prstk_lock == NULL) { |
- PR_Free(stack->prstk_name); |
- PR_DELETE(stack); |
- return NULL; |
- } |
-#endif /* !_PR_HAVE_ATOMIC_CAS */ |
- |
- stack->prstk_head.prstk_elem_next = NULL; |
- |
- return stack; |
-} |
- |
-PR_IMPLEMENT(PRStatus) |
-PR_DestroyStack(PRStack *stack) |
-{ |
- if (stack->prstk_head.prstk_elem_next != NULL) { |
- PR_SetError(PR_INVALID_STATE_ERROR, 0); |
- return PR_FAILURE; |
- } |
- |
- if (stack->prstk_name) |
- PR_Free(stack->prstk_name); |
-#ifndef _PR_HAVE_ATOMIC_CAS |
- PR_DestroyLock(stack->prstk_lock); |
-#endif /* !_PR_HAVE_ATOMIC_CAS */ |
- PR_DELETE(stack); |
- |
- return PR_SUCCESS; |
-} |
- |
-#ifndef _PR_HAVE_ATOMIC_CAS |
- |
-PR_IMPLEMENT(void) |
-PR_StackPush(PRStack *stack, PRStackElem *stack_elem) |
-{ |
- PR_Lock(stack->prstk_lock); |
- stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next; |
- stack->prstk_head.prstk_elem_next = stack_elem; |
- PR_Unlock(stack->prstk_lock); |
- return; |
-} |
- |
-PR_IMPLEMENT(PRStackElem *) |
-PR_StackPop(PRStack *stack) |
-{ |
-PRStackElem *element; |
- |
- PR_Lock(stack->prstk_lock); |
- element = stack->prstk_head.prstk_elem_next; |
- if (element != NULL) { |
- stack->prstk_head.prstk_elem_next = element->prstk_elem_next; |
- element->prstk_elem_next = NULL; /* debugging aid */ |
- } |
- PR_Unlock(stack->prstk_lock); |
- return element; |
-} |
-#endif /* !_PR_HAVE_ATOMIC_CAS */ |