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