blob: cfa614370103d307acdba5aab9edb53fc28a6685 [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
Austin Schuh745610d2015-09-06 18:19:50 -0700125inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
126 MemoryBarrier();
127 *ptr = value;
128}
129
130inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
131 return *ptr;
132}
133
134inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
135 Atomic32 value = *ptr;
136 MemoryBarrier();
137 return value;
138}
139
Austin Schuh745610d2015-09-06 18:19:50 -0700140
141// 64-bit versions are not implemented yet.
142
143inline void NotImplementedFatalError(const char *function_name) {
144 fprintf(stderr, "64-bit %s() not implemented on this platform\n",
145 function_name);
146 abort();
147}
148
149inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
150 Atomic64 old_value,
151 Atomic64 new_value) {
152 NotImplementedFatalError("NoBarrier_CompareAndSwap");
153 return 0;
154}
155
156inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
157 Atomic64 new_value) {
158 NotImplementedFatalError("NoBarrier_AtomicExchange");
159 return 0;
160}
161
162inline Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr,
163 Atomic64 new_value) {
164 // pLinuxKernelCmpxchg already has acquire and release barrier semantics.
165 return NoBarrier_AtomicExchange(ptr, new_value);
166}
167
168inline Atomic64 Release_AtomicExchange(volatile Atomic64* ptr,
169 Atomic64 new_value) {
170 // pLinuxKernelCmpxchg already has acquire and release barrier semantics.
171 return NoBarrier_AtomicExchange(ptr, new_value);
172}
173
174inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
175 NotImplementedFatalError("NoBarrier_Store");
176}
177
Austin Schuh745610d2015-09-06 18:19:50 -0700178inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
179 NotImplementedFatalError("Release_Store");
180}
181
182inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
183 NotImplementedFatalError("NoBarrier_Load");
184 return 0;
185}
186
187inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
188 NotImplementedFatalError("Atomic64 Acquire_Load");
189 return 0;
190}
191
Austin Schuh745610d2015-09-06 18:19:50 -0700192inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
193 Atomic64 old_value,
194 Atomic64 new_value) {
195 NotImplementedFatalError("Atomic64 Acquire_CompareAndSwap");
196 return 0;
197}
198
199inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
200 Atomic64 old_value,
201 Atomic64 new_value) {
202 NotImplementedFatalError("Atomic64 Release_CompareAndSwap");
203 return 0;
204}
205
206} // namespace base::subtle
207} // namespace base
208
209#endif // BASE_ATOMICOPS_INTERNALS_ARM_GENERIC_H_