1
! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3
! The contents of this file are subject to the Mozilla Public
4
! License Version 1.1 (the "License"); you may not use this file
5
! except in compliance with the License. You may obtain a copy of
6
! the License at http://www.mozilla.org/MPL/
8
! Software distributed under the License is distributed on an "AS
9
! IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
! implied. See the License for the specific language governing
11
! rights and limitations under the License.
13
! The Original Code is the Netscape Portable Runtime (NSPR).
15
! The Initial Developer of the Original Code is Netscape
16
! Communications Corporation. Portions created by Netscape are
17
! Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
! Alternatively, the contents of this file may be used under the
23
! terms of the GNU General Public License Version 2 or later (the
24
! "GPL"), in which case the provisions of the GPL are applicable
25
! instead of those above. If you wish to allow use of your
26
! version of this file only under the terms of the GPL and not to
27
! allow others to use your version of this file under the MPL,
28
! indicate your decision by deleting the provisions above and
29
! replace them with the notice and other provisions required by
30
! the GPL. If you do not delete the provisions above, a recipient
31
! may use your version of this file under either the MPL or the
36
! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc)
37
! using CAS (compare-and-swap) atomic instructions
39
! this MUST be compiled with an ultrasparc-aware assembler
41
! standard asm linkage macros; this module must be compiled
42
! with the -P option (use C preprocessor)
44
#include <sys/asm_linkage.h>
46
! ======================================================================
48
! Perform the sequence a = a + 1 atomically with respect to other
49
! fetch-and-adds to location a in a wait-free fashion.
51
! usage : val = PR_AtomicIncrement(address)
52
! return: current value (you'd think this would be old val)
54
! -----------------------
55
! Note on REGISTER USAGE:
56
! as this is a LEAF procedure, a new stack frame is not created;
57
! we use the caller's stack frame so what would normally be %i (input)
58
! registers are actually %o (output registers). Also, we must not
59
! overwrite the contents of %l (local) registers as they are not
60
! assumed to be volatile during calls.
62
! So, the registers used are:
63
! %o0 [input] - the address of the value to increment
64
! %o1 [local] - work register
65
! %o2 [local] - work register
66
! %o3 [local] - work register
67
! -----------------------
69
ENTRY(PR_AtomicIncrement) ! standard assembler/ELF prologue
72
ld [%o0], %o2 ! set o2 to the current value
73
add %o2, 0x1, %o3 ! calc the new value
74
mov %o3, %o1 ! save the return value
75
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
76
cmp %o2, %o3 ! see if we set the value
77
bne retryAI ! if not, try again
78
nop ! empty out the branch pipeline
79
retl ! return back to the caller
80
mov %o1, %o0 ! set the return code to the new value
82
SET_SIZE(PR_AtomicIncrement) ! standard assembler/ELF epilogue
87
! ======================================================================
90
! ======================================================================
92
! Perform the sequence a = a - 1 atomically with respect to other
93
! fetch-and-decs to location a in a wait-free fashion.
95
! usage : val = PR_AtomicDecrement(address)
96
! return: current value (you'd think this would be old val)
98
! -----------------------
99
! Note on REGISTER USAGE:
100
! as this is a LEAF procedure, a new stack frame is not created;
101
! we use the caller's stack frame so what would normally be %i (input)
102
! registers are actually %o (output registers). Also, we must not
103
! overwrite the contents of %l (local) registers as they are not
104
! assumed to be volatile during calls.
106
! So, the registers used are:
107
! %o0 [input] - the address of the value to increment
108
! %o1 [local] - work register
109
! %o2 [local] - work register
110
! %o3 [local] - work register
111
! -----------------------
113
ENTRY(PR_AtomicDecrement) ! standard assembler/ELF prologue
116
ld [%o0], %o2 ! set o2 to the current value
117
sub %o2, 0x1, %o3 ! calc the new value
118
mov %o3, %o1 ! save the return value
119
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
120
cmp %o2, %o3 ! see if we set the value
121
bne retryAD ! if not, try again
122
nop ! empty out the branch pipeline
123
retl ! return back to the caller
124
mov %o1, %o0 ! set the return code to the new value
126
SET_SIZE(PR_AtomicDecrement) ! standard assembler/ELF epilogue
131
! ======================================================================
134
! ======================================================================
136
! Perform the sequence a = b atomically with respect to other
137
! fetch-and-stores to location a in a wait-free fashion.
139
! usage : old_val = PR_AtomicSet(address, newval)
141
! -----------------------
142
! Note on REGISTER USAGE:
143
! as this is a LEAF procedure, a new stack frame is not created;
144
! we use the caller's stack frame so what would normally be %i (input)
145
! registers are actually %o (output registers). Also, we must not
146
! overwrite the contents of %l (local) registers as they are not
147
! assumed to be volatile during calls.
149
! So, the registers used are:
150
! %o0 [input] - the address of the value to increment
151
! %o1 [input] - the new value to set for [%o0]
152
! %o2 [local] - work register
153
! %o3 [local] - work register
154
! -----------------------
156
ENTRY(PR_AtomicSet) ! standard assembler/ELF prologue
159
ld [%o0], %o2 ! set o2 to the current value
160
mov %o1, %o3 ! set up the new value
161
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
162
cmp %o2, %o3 ! see if we set the value
163
bne retryAS ! if not, try again
164
nop ! empty out the branch pipeline
165
retl ! return back to the caller
166
mov %o3, %o0 ! set the return code to the prev value
168
SET_SIZE(PR_AtomicSet) ! standard assembler/ELF epilogue
173
! ======================================================================
176
! ======================================================================
178
! Perform the sequence a = a + b atomically with respect to other
179
! fetch-and-adds to location a in a wait-free fashion.
181
! usage : newval = PR_AtomicAdd(address, val)
182
! return: the value after addition
184
ENTRY(PR_AtomicAdd) ! standard assembler/ELF prologue
187
ld [%o0], %o2 ! set o2 to the current value
188
add %o2, %o1, %o3 ! calc the new value
189
mov %o3, %o4 ! save the return value
190
cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed
191
cmp %o2, %o3 ! see if we set the value
192
bne retryAA ! if not, try again
193
nop ! empty out the branch pipeline
194
retl ! return back to the caller
195
mov %o4, %o0 ! set the return code to the new value
197
SET_SIZE(PR_AtomicAdd) ! standard assembler/ELF epilogue