atomic-utils.h 4.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_ATOMIC_UTILS_H_
#define V8_ATOMIC_UTILS_H_

#include <limits.h>

#include "src/base/atomicops.h"
#include "src/base/macros.h"

namespace v8 {
namespace internal {

16 17 18 19 20 21
template <class T>
class AtomicNumber {
 public:
  AtomicNumber() : value_(0) {}
  explicit AtomicNumber(T initial) : value_(initial) {}

22 23 24 25
  // Returns the newly set value.
  V8_INLINE T Increment(T increment) {
    return static_cast<T>(base::Barrier_AtomicIncrement(
        &value_, static_cast<base::AtomicWord>(increment)));
26 27
  }

28
  V8_INLINE T Value() { return static_cast<T>(base::Acquire_Load(&value_)); }
29 30

  V8_INLINE void SetValue(T new_value) {
31
    base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value));
32 33
  }

34 35 36 37 38
  V8_INLINE T operator=(T value) {
    SetValue(value);
    return value;
  }

39 40 41 42 43 44 45 46 47
 private:
  STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));

  base::AtomicWord value_;
};


// Flag using T atomically. Also accepts void* as T.
template <typename T>
48 49
class AtomicValue {
 public:
50 51
  AtomicValue() : value_(0) {}

52 53
  explicit AtomicValue(T initial)
      : value_(cast_helper<T>::to_storage_type(initial)) {}
54

55
  V8_INLINE T Value() {
56
    return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
57 58
  }

59
  V8_INLINE bool TrySetValue(T old_value, T new_value) {
60
    return base::Release_CompareAndSwap(
61 62 63 64
               &value_, cast_helper<T>::to_storage_type(old_value),
               cast_helper<T>::to_storage_type(new_value)) ==
           cast_helper<T>::to_storage_type(old_value);
  }
65

66 67
  V8_INLINE void SetValue(T new_value) {
    base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value));
68 69 70
  }

 private:
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));

  template <typename S>
  struct cast_helper {
    static base::AtomicWord to_storage_type(S value) {
      return static_cast<base::AtomicWord>(value);
    }
    static S to_return_type(base::AtomicWord value) {
      return static_cast<S>(value);
    }
  };

  template <typename S>
  struct cast_helper<S*> {
    static base::AtomicWord to_storage_type(S* value) {
      return reinterpret_cast<base::AtomicWord>(value);
    }
    static S* to_return_type(base::AtomicWord value) {
      return reinterpret_cast<S*>(value);
    }
  };

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
  base::AtomicWord value_;
};


// See utils.h for EnumSet. Storage is always base::AtomicWord.
// Requirements on E:
// - No explicit values.
// - E::kLastValue defined to be the last actually used value.
//
// Example:
// enum E { kA, kB, kC, kLastValue = kC };
template <class E>
class AtomicEnumSet {
 public:
  explicit AtomicEnumSet(base::AtomicWord bits = 0) : bits_(bits) {}

  bool IsEmpty() const { return ToIntegral() == 0; }

  bool Contains(E element) const { return (ToIntegral() & Mask(element)) != 0; }
  bool ContainsAnyOf(const AtomicEnumSet& set) const {
    return (ToIntegral() & set.ToIntegral()) != 0;
  }

116
  void RemoveAll() { base::Release_Store(&bits_, 0); }
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

  bool operator==(const AtomicEnumSet& set) const {
    return ToIntegral() == set.ToIntegral();
  }

  bool operator!=(const AtomicEnumSet& set) const {
    return ToIntegral() != set.ToIntegral();
  }

  AtomicEnumSet<E> operator|(const AtomicEnumSet& set) const {
    return AtomicEnumSet<E>(ToIntegral() | set.ToIntegral());
  }

// The following operations modify the underlying storage.

#define ATOMIC_SET_WRITE(OP, NEW_VAL)                                     \
  do {                                                                    \
    base::AtomicWord old;                                                 \
    do {                                                                  \
      old = base::Acquire_Load(&bits_);                                   \
    } while (base::Release_CompareAndSwap(&bits_, old, old OP NEW_VAL) != \
             old);                                                        \
  } while (false)

  void Add(E element) { ATOMIC_SET_WRITE(|, Mask(element)); }

  void Add(const AtomicEnumSet& set) { ATOMIC_SET_WRITE(|, set.ToIntegral()); }

145
  void Remove(E element) { ATOMIC_SET_WRITE(&, ~Mask(element)); }
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

  void Remove(const AtomicEnumSet& set) {
    ATOMIC_SET_WRITE(&, ~set.ToIntegral());
  }

  void Intersect(const AtomicEnumSet& set) {
    ATOMIC_SET_WRITE(&, set.ToIntegral());
  }

#undef ATOMIC_SET_OP

 private:
  // Check whether there's enough storage to hold E.
  STATIC_ASSERT(E::kLastValue < (sizeof(base::AtomicWord) * CHAR_BIT));

  V8_INLINE base::AtomicWord ToIntegral() const {
162
    return base::Acquire_Load(&bits_);
163 164 165 166 167 168 169 170 171 172 173 174 175
  }

  V8_INLINE base::AtomicWord Mask(E element) const {
    return static_cast<base::AtomicWord>(1) << element;
  }

  base::AtomicWord bits_;
};

}  // namespace internal
}  // namespace v8

#endif  // #define V8_ATOMIC_UTILS_H_