andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* GLOBAL FUNCTIONS: andre@0: ** DESCRIPTION: andre@0: ** PR Atomic operations andre@0: */ andre@0: andre@0: #ifndef pratom_h___ andre@0: #define pratom_h___ andre@0: andre@0: #include "prtypes.h" andre@0: #include "prlock.h" andre@0: andre@0: PR_BEGIN_EXTERN_C andre@0: andre@0: /* andre@0: ** FUNCTION: PR_AtomicIncrement andre@0: ** DESCRIPTION: andre@0: ** Atomically increment a 32 bit value. andre@0: ** INPUTS: andre@0: ** val: a pointer to the value to increment andre@0: ** RETURN: andre@0: ** the returned value is the result of the increment andre@0: */ andre@0: NSPR_API(PRInt32) PR_AtomicIncrement(PRInt32 *val); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_AtomicDecrement andre@0: ** DESCRIPTION: andre@0: ** Atomically decrement a 32 bit value. andre@0: ** INPUTS: andre@0: ** val: a pointer to the value to decrement andre@0: ** RETURN: andre@0: ** the returned value is the result of the decrement andre@0: */ andre@0: NSPR_API(PRInt32) PR_AtomicDecrement(PRInt32 *val); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_AtomicSet andre@0: ** DESCRIPTION: andre@0: ** Atomically set a 32 bit value. andre@0: ** INPUTS: andre@0: ** val: A pointer to a 32 bit value to be set andre@0: ** newval: The newvalue to assign to val andre@0: ** RETURN: andre@0: ** Returns the prior value andre@0: */ andre@0: NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_AtomicAdd andre@0: ** DESCRIPTION: andre@0: ** Atomically add a 32 bit value. andre@0: ** INPUTS: andre@0: ** ptr: a pointer to the value to increment andre@0: ** val: value to be added andre@0: ** RETURN: andre@0: ** the returned value is the result of the addition andre@0: */ andre@0: NSPR_API(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); andre@0: andre@0: /* andre@0: ** MACRO: PR_ATOMIC_INCREMENT andre@0: ** MACRO: PR_ATOMIC_DECREMENT andre@0: ** MACRO: PR_ATOMIC_SET andre@0: ** MACRO: PR_ATOMIC_ADD andre@0: ** DESCRIPTION: andre@0: ** Macro versions of the atomic operations. They may be implemented andre@0: ** as compiler intrinsics. andre@0: ** andre@0: ** IMPORTANT NOTE TO NSPR MAINTAINERS: andre@0: ** Implement these macros with compiler intrinsics only on platforms andre@0: ** where the PR_AtomicXXX functions are truly atomic (i.e., where the andre@0: ** configuration macro _PR_HAVE_ATOMIC_OPS is defined). Otherwise, andre@0: ** the macros and functions won't be compatible and can't be used andre@0: ** interchangeably. andre@0: */ andre@0: #if defined(_WIN32) && !defined(_WIN32_WCE) && \ andre@0: (!defined(_MSC_VER) || (_MSC_VER >= 1310)) andre@0: andre@0: long __cdecl _InterlockedIncrement(long volatile *Addend); andre@0: long __cdecl _InterlockedDecrement(long volatile *Addend); andre@0: long __cdecl _InterlockedExchange(long volatile *Target, long Value); andre@0: long __cdecl _InterlockedExchangeAdd(long volatile *Addend, long Value); andre@0: andre@0: #ifdef _MSC_VER andre@0: #pragma intrinsic(_InterlockedIncrement) andre@0: #pragma intrinsic(_InterlockedDecrement) andre@0: #pragma intrinsic(_InterlockedExchange) andre@0: #pragma intrinsic(_InterlockedExchangeAdd) andre@0: #endif andre@0: andre@0: #define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement((long volatile *)(val)) andre@0: #define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement((long volatile *)(val)) andre@0: #define PR_ATOMIC_SET(val, newval) \ andre@0: _InterlockedExchange((long volatile *)(val), (long)(newval)) andre@0: #define PR_ATOMIC_ADD(ptr, val) \ andre@0: (_InterlockedExchangeAdd((long volatile *)(ptr), (long)(val)) + (val)) andre@0: andre@0: #elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \ andre@0: ((defined(__APPLE__) && \ andre@0: (defined(__ppc__) || defined(__i386__) || defined(__x86_64__))) || \ andre@0: (defined(__linux__) && \ andre@0: ((defined(__i386__) && \ andre@0: defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \ andre@0: defined(__ia64__) || defined(__x86_64__) || \ andre@0: (defined(__powerpc__) && !defined(__powerpc64__)) || \ andre@0: (defined(__arm__) && \ andre@0: defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \ andre@0: defined(__aarch64__) || defined(__alpha)))) andre@0: andre@0: /* andre@0: * Because the GCC manual warns that some processors may support andre@0: * reduced functionality of __sync_lock_test_and_set, we test for the andre@0: * processors that we believe support a full atomic exchange operation. andre@0: */ andre@0: andre@0: #define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1) andre@0: #define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1) andre@0: #define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval) andre@0: #define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val) andre@0: andre@0: #else andre@0: andre@0: #define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val) andre@0: #define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val) andre@0: #define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval) andre@0: #define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val) andre@0: andre@0: #endif andre@0: andre@0: /* andre@0: ** LIFO linked-list (stack) andre@0: */ andre@0: typedef struct PRStackElemStr PRStackElem; andre@0: andre@0: struct PRStackElemStr { andre@0: PRStackElem *prstk_elem_next; /* next pointer MUST be at offset 0; andre@0: assembly language code relies on this */ andre@0: }; andre@0: andre@0: typedef struct PRStackStr PRStack; andre@0: andre@0: /* andre@0: ** FUNCTION: PR_CreateStack andre@0: ** DESCRIPTION: andre@0: ** Create a stack, a LIFO linked list andre@0: ** INPUTS: andre@0: ** stack_name: a pointer to string containing the name of the stack andre@0: ** RETURN: andre@0: ** A pointer to the created stack, if successful, else NULL. andre@0: */ andre@0: NSPR_API(PRStack *) PR_CreateStack(const char *stack_name); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_StackPush andre@0: ** DESCRIPTION: andre@0: ** Push an element on the top of the stack andre@0: ** INPUTS: andre@0: ** stack: pointer to the stack andre@0: ** stack_elem: pointer to the stack element andre@0: ** RETURN: andre@0: ** None andre@0: */ andre@0: NSPR_API(void) PR_StackPush(PRStack *stack, PRStackElem *stack_elem); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_StackPop andre@0: ** DESCRIPTION: andre@0: ** Remove the element on the top of the stack andre@0: ** INPUTS: andre@0: ** stack: pointer to the stack andre@0: ** RETURN: andre@0: ** A pointer to the stack element removed from the top of the stack, andre@0: ** if non-empty, andre@0: ** else NULL andre@0: */ andre@0: NSPR_API(PRStackElem *) PR_StackPop(PRStack *stack); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_DestroyStack andre@0: ** DESCRIPTION: andre@0: ** Destroy the stack andre@0: ** INPUTS: andre@0: ** stack: pointer to the stack andre@0: ** RETURN: andre@0: ** PR_SUCCESS - if successfully deleted andre@0: ** PR_FAILURE - if the stack is not empty andre@0: ** PR_GetError will return andre@0: ** PR_INVALID_STATE_ERROR - stack is not empty andre@0: */ andre@0: NSPR_API(PRStatus) PR_DestroyStack(PRStack *stack); andre@0: andre@0: PR_END_EXTERN_C andre@0: andre@0: #endif /* pratom_h___ */