summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/include/pratom.h
blob: 11a8aaedc95782bdcbfd010c452e885f98af0c58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* -*- 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/. */

/* GLOBAL FUNCTIONS:
** DESCRIPTION:
**     PR Atomic operations
*/

#ifndef pratom_h___
#define pratom_h___

#include "prtypes.h"
#include "prlock.h"

PR_BEGIN_EXTERN_C

/*
** FUNCTION: PR_AtomicIncrement
** DESCRIPTION:
**    Atomically increment a 32 bit value.
** INPUTS:
**    val:  a pointer to the value to increment
** RETURN:
**    the returned value is the result of the increment
*/
NSPR_API(PRInt32)   PR_AtomicIncrement(PRInt32 *val);

/*
** FUNCTION: PR_AtomicDecrement
** DESCRIPTION:
**    Atomically decrement a 32 bit value.
** INPUTS:
**    val:  a pointer to the value to decrement
** RETURN:
**    the returned value is the result of the decrement
*/
NSPR_API(PRInt32)   PR_AtomicDecrement(PRInt32 *val);

/*
** FUNCTION: PR_AtomicSet
** DESCRIPTION:
**    Atomically set a 32 bit value.
** INPUTS:
**    val: A pointer to a 32 bit value to be set
**    newval: The newvalue to assign to val
** RETURN:
**    Returns the prior value
*/
NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval);

/*
** FUNCTION: PR_AtomicAdd
** DESCRIPTION:
**    Atomically add a 32 bit value.
** INPUTS:
**    ptr:  a pointer to the value to increment
**    val:  value to be added
** RETURN:
**    the returned value is the result of the addition
*/
NSPR_API(PRInt32)   PR_AtomicAdd(PRInt32 *ptr, PRInt32 val);

/*
** MACRO: PR_ATOMIC_INCREMENT
** MACRO: PR_ATOMIC_DECREMENT
** MACRO: PR_ATOMIC_SET
** MACRO: PR_ATOMIC_ADD
** DESCRIPTION:
**    Macro versions of the atomic operations.  They may be implemented
**    as compiler intrinsics.
**
** IMPORTANT NOTE TO NSPR MAINTAINERS:
**    Implement these macros with compiler intrinsics only on platforms
**    where the PR_AtomicXXX functions are truly atomic (i.e., where the
**    configuration macro _PR_HAVE_ATOMIC_OPS is defined).  Otherwise,
**    the macros and functions won't be compatible and can't be used
**    interchangeably.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && \
    (!defined(_MSC_VER) || (_MSC_VER >= 1310))

#include <intrin.h>

#ifdef _MSC_VER
#pragma intrinsic(_InterlockedIncrement)
#pragma intrinsic(_InterlockedDecrement)
#pragma intrinsic(_InterlockedExchange)
#pragma intrinsic(_InterlockedExchangeAdd)
#endif

#define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement((long volatile *)(val))
#define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement((long volatile *)(val))
#define PR_ATOMIC_SET(val, newval) \
        _InterlockedExchange((long volatile *)(val), (long)(newval))
#define PR_ATOMIC_ADD(ptr, val) \
        (_InterlockedExchangeAdd((long volatile *)(ptr), (long)(val)) + (val))

#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \
      ((defined(__APPLE__) && \
           (defined(__ppc__) || defined(__i386__) || defined(__x86_64__))) || \
       (defined(__linux__) && \
           ((defined(__i386__) && \
           defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \
           defined(__ia64__) || defined(__x86_64__) || \
           defined(__powerpc__) || \
           (defined(__arm__) && \
           defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \
           defined(__aarch64__) || defined(__alpha) || \
           (defined(__mips__) && \
           defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)))))

/*
 * Because the GCC manual warns that some processors may support
 * reduced functionality of __sync_lock_test_and_set, we test for the
 * processors that we believe support a full atomic exchange operation.
 */

#define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1)
#define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1)
#define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval)
#define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val)

#else

#define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val)
#define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val)
#define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval)
#define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val)

#endif

/*
** LIFO linked-list (stack)
*/
typedef struct PRStackElemStr PRStackElem;

struct PRStackElemStr {
    PRStackElem *prstk_elem_next;   /* next pointer MUST be at offset 0;
                                      assembly language code relies on this */
};

typedef struct PRStackStr PRStack;

/*
** FUNCTION: PR_CreateStack
** DESCRIPTION:
**    Create a stack, a LIFO linked list
** INPUTS:
**    stack_name:  a pointer to string containing the name of the stack
** RETURN:
**    A pointer to the created stack, if successful, else NULL.
*/
NSPR_API(PRStack *) PR_CreateStack(const char *stack_name);

/*
** FUNCTION: PR_StackPush
** DESCRIPTION:
**    Push an element on the top of the stack
** INPUTS:
**    stack:        pointer to the stack
**    stack_elem:   pointer to the stack element
** RETURN:
**    None
*/
NSPR_API(void)          PR_StackPush(PRStack *stack, PRStackElem *stack_elem);

/*
** FUNCTION: PR_StackPop
** DESCRIPTION:
**    Remove the element on the top of the stack
** INPUTS:
**    stack:        pointer to the stack
** RETURN:
**    A pointer to the stack element removed from the top of the stack,
**    if non-empty,
**    else NULL
*/
NSPR_API(PRStackElem *) PR_StackPop(PRStack *stack);

/*
** FUNCTION: PR_DestroyStack
** DESCRIPTION:
**    Destroy the stack
** INPUTS:
**    stack:        pointer to the stack
** RETURN:
**    PR_SUCCESS - if successfully deleted
**    PR_FAILURE - if the stack is not empty
**                  PR_GetError will return
**                      PR_INVALID_STATE_ERROR - stack is not empty
*/
NSPR_API(PRStatus)      PR_DestroyStack(PRStack *stack);

PR_END_EXTERN_C

#endif /* pratom_h___ */