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