1// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file is an internal atomic implementation, use base/atomicops.h instead.
6
7#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
8#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
9
10#include <windows.h>
11
12#include <intrin.h>
13
14#include "base/macros.h"
15#include "build/build_config.h"
16
17#if defined(ARCH_CPU_64_BITS)
18// windows.h #defines this (only on x64). This causes problems because the
19// public API also uses MemoryBarrier at the public name for this fence. So, on
20// X64, undef it, and call its documented
21// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
22// implementation directly.
23#undef MemoryBarrier
24#endif
25
26namespace base {
27namespace subtle {
28
29inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
30                                         Atomic32 old_value,
31                                         Atomic32 new_value) {
32  LONG result = _InterlockedCompareExchange(
33      reinterpret_cast<volatile LONG*>(ptr),
34      static_cast<LONG>(new_value),
35      static_cast<LONG>(old_value));
36  return static_cast<Atomic32>(result);
37}
38
39inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
40                                         Atomic32 new_value) {
41  LONG result = _InterlockedExchange(
42      reinterpret_cast<volatile LONG*>(ptr),
43      static_cast<LONG>(new_value));
44  return static_cast<Atomic32>(result);
45}
46
47inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
48                                        Atomic32 increment) {
49  return _InterlockedExchangeAdd(
50      reinterpret_cast<volatile LONG*>(ptr),
51      static_cast<LONG>(increment)) + increment;
52}
53
54inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
55                                          Atomic32 increment) {
56  return Barrier_AtomicIncrement(ptr, increment);
57}
58
59inline void MemoryBarrier() {
60#if defined(ARCH_CPU_64_BITS)
61  // See #undef and note at the top of this file.
62  __faststorefence();
63#else
64  // We use MemoryBarrier from WinNT.h
65  ::MemoryBarrier();
66#endif
67}
68
69inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
70                                       Atomic32 old_value,
71                                       Atomic32 new_value) {
72  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
73}
74
75inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
76                                       Atomic32 old_value,
77                                       Atomic32 new_value) {
78  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
79}
80
81inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
82  *ptr = value;
83}
84
85inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
86  NoBarrier_AtomicExchange(ptr, value);
87              // acts as a barrier in this implementation
88}
89
90inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
91  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
92  // See comments in Atomic64 version of Release_Store() below.
93}
94
95inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
96  return *ptr;
97}
98
99inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
100  Atomic32 value = *ptr;
101  return value;
102}
103
104inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
105  MemoryBarrier();
106  return *ptr;
107}
108
109#if defined(_WIN64)
110
111// 64-bit low-level operations on 64-bit platform.
112
113static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
114
115inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
116                                         Atomic64 old_value,
117                                         Atomic64 new_value) {
118  PVOID result = InterlockedCompareExchangePointer(
119    reinterpret_cast<volatile PVOID*>(ptr),
120    reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
121  return reinterpret_cast<Atomic64>(result);
122}
123
124inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
125                                         Atomic64 new_value) {
126  PVOID result = InterlockedExchangePointer(
127    reinterpret_cast<volatile PVOID*>(ptr),
128    reinterpret_cast<PVOID>(new_value));
129  return reinterpret_cast<Atomic64>(result);
130}
131
132inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
133                                        Atomic64 increment) {
134  return InterlockedExchangeAdd64(
135      reinterpret_cast<volatile LONGLONG*>(ptr),
136      static_cast<LONGLONG>(increment)) + increment;
137}
138
139inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
140                                          Atomic64 increment) {
141  return Barrier_AtomicIncrement(ptr, increment);
142}
143
144inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
145  *ptr = value;
146}
147
148inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
149  NoBarrier_AtomicExchange(ptr, value);
150              // acts as a barrier in this implementation
151}
152
153inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
154  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
155
156  // When new chips come out, check:
157  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
158  //  System Programming Guide, Chatper 7: Multiple-processor management,
159  //  Section 7.2, Memory Ordering.
160  // Last seen at:
161  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
162}
163
164inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
165  return *ptr;
166}
167
168inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
169  Atomic64 value = *ptr;
170  return value;
171}
172
173inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
174  MemoryBarrier();
175  return *ptr;
176}
177
178inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
179                                       Atomic64 old_value,
180                                       Atomic64 new_value) {
181  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
182}
183
184inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
185                                       Atomic64 old_value,
186                                       Atomic64 new_value) {
187  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
188}
189
190
191#endif  // defined(_WIN64)
192
193}  // namespace subtle
194}  // namespace base
195
196#endif  // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
197