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