blob: d0f941309bb7e5d04a5e432dd208663b964e329d [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2003, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30// ---
31//
32// Author: Lei Zhang, Sasha Levitskiy
33//
34// This file is an internal atomic implementation, use base/atomicops.h instead.
35//
36// LinuxKernelCmpxchg is from Google Gears.
37
38#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GENERIC_H_
39#define BASE_ATOMICOPS_INTERNALS_ARM_GENERIC_H_
40
41#include <stdio.h>
42#include <stdlib.h>
43#include "base/basictypes.h"
44
45typedef int32_t Atomic32;
46
47namespace base {
48namespace subtle {
49
50typedef int64_t Atomic64;
51
52// 0xffff0fc0 is the hard coded address of a function provided by
53// the kernel which implements an atomic compare-exchange. On older
54// ARM architecture revisions (pre-v6) this may be implemented using
55// a syscall. This address is stable, and in active use (hard coded)
56// by at least glibc-2.7 and the Android C library.
57// pLinuxKernelCmpxchg has both acquire and release barrier sematincs.
58typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
59 Atomic32 new_value,
60 volatile Atomic32* ptr);
61LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg ATTRIBUTE_WEAK =
62 (LinuxKernelCmpxchgFunc) 0xffff0fc0;
63
64typedef void (*LinuxKernelMemoryBarrierFunc)(void);
65LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier ATTRIBUTE_WEAK =
66 (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
67
68
69inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
70 Atomic32 old_value,
71 Atomic32 new_value) {
72 Atomic32 prev_value = *ptr;
73 do {
74 if (!pLinuxKernelCmpxchg(old_value, new_value,
75 const_cast<Atomic32*>(ptr))) {
76 return old_value;
77 }
78 prev_value = *ptr;
79 } while (prev_value == old_value);
80 return prev_value;
81}
82
83inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
84 Atomic32 new_value) {
85 Atomic32 old_value;
86 do {
87 old_value = *ptr;
88 } while (pLinuxKernelCmpxchg(old_value, new_value,
89 const_cast<Atomic32*>(ptr)));
90 return old_value;
91}
92
93inline Atomic32 Acquire_AtomicExchange(volatile Atomic32* ptr,
94 Atomic32 new_value) {
95 // pLinuxKernelCmpxchg already has acquire and release barrier semantics.
96 return NoBarrier_AtomicExchange(ptr, new_value);
97}
98
99inline Atomic32 Release_AtomicExchange(volatile Atomic32* ptr,
100 Atomic32 new_value) {
101 // pLinuxKernelCmpxchg already has acquire and release barrier semantics.
102 return NoBarrier_AtomicExchange(ptr, new_value);
103}
104
105inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
106 Atomic32 old_value,
107 Atomic32 new_value) {
108 return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
109}
110
111inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
112 Atomic32 old_value,
113 Atomic32 new_value) {
114 return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
115}
116
117inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
118 *ptr = value;
119}
120
121inline void MemoryBarrier() {
122 pLinuxKernelMemoryBarrier();
123}
124
125inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
126 *ptr = value;
127 MemoryBarrier();
128}
129
130inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
131 MemoryBarrier();
132 *ptr = value;
133}
134
135inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
136 return *ptr;
137}
138
139inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
140 Atomic32 value = *ptr;
141 MemoryBarrier();
142 return value;
143}
144
145inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
146 MemoryBarrier();
147 return *ptr;
148}
149
150
151// 64-bit versions are not implemented yet.
152
153inline void NotImplementedFatalError(const char *function_name) {
154 fprintf(stderr, "64-bit %s() not implemented on this platform\n",
155 function_name);
156 abort();
157}
158
159inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
160 Atomic64 old_value,
161 Atomic64 new_value) {
162 NotImplementedFatalError("NoBarrier_CompareAndSwap");
163 return 0;
164}
165
166inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
167 Atomic64 new_value) {
168 NotImplementedFatalError("NoBarrier_AtomicExchange");
169 return 0;
170}
171
172inline Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr,
173 Atomic64 new_value) {
174 // pLinuxKernelCmpxchg already has acquire and release barrier semantics.
175 return NoBarrier_AtomicExchange(ptr, new_value);
176}
177
178inline Atomic64 Release_AtomicExchange(volatile Atomic64* ptr,
179 Atomic64 new_value) {
180 // pLinuxKernelCmpxchg already has acquire and release barrier semantics.
181 return NoBarrier_AtomicExchange(ptr, new_value);
182}
183
184inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
185 NotImplementedFatalError("NoBarrier_Store");
186}
187
188inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
189 NotImplementedFatalError("Acquire_Store64");
190}
191
192inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
193 NotImplementedFatalError("Release_Store");
194}
195
196inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
197 NotImplementedFatalError("NoBarrier_Load");
198 return 0;
199}
200
201inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
202 NotImplementedFatalError("Atomic64 Acquire_Load");
203 return 0;
204}
205
206inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
207 NotImplementedFatalError("Atomic64 Release_Load");
208 return 0;
209}
210
211inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
212 Atomic64 old_value,
213 Atomic64 new_value) {
214 NotImplementedFatalError("Atomic64 Acquire_CompareAndSwap");
215 return 0;
216}
217
218inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
219 Atomic64 old_value,
220 Atomic64 new_value) {
221 NotImplementedFatalError("Atomic64 Release_CompareAndSwap");
222 return 0;
223}
224
225} // namespace base::subtle
226} // namespace base
227
228#endif // BASE_ATOMICOPS_INTERNALS_ARM_GENERIC_H_