blob: ea8f89cf2b3b3f9380ea827568a0b3b1a03d7fea [file] [log] [blame]
Mathieu Chartierd8195f12012-10-05 12:21:28 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_GC_ACCOUNTING_ATOMIC_STACK_H_
18#define ART_RUNTIME_GC_ACCOUNTING_ATOMIC_STACK_H_
Mathieu Chartierd8195f12012-10-05 12:21:28 -070019
20#include <string>
21
Ian Rogersef7d42f2014-01-06 12:55:46 -080022#include "atomic.h"
Elliott Hughes07ed66b2012-12-12 18:34:25 -080023#include "base/logging.h"
Elliott Hughes76160052012-12-12 16:31:20 -080024#include "base/macros.h"
Mathieu Chartierd8195f12012-10-05 12:21:28 -070025#include "UniquePtr.h"
Mathieu Chartierd8195f12012-10-05 12:21:28 -070026#include "mem_map.h"
27#include "utils.h"
28
29namespace art {
Ian Rogers1d54e732013-05-02 21:10:01 -070030namespace gc {
31namespace accounting {
Mathieu Chartierd8195f12012-10-05 12:21:28 -070032
33template <typename T>
34class AtomicStack {
35 public:
36 // Capacity is how many elements we can store in the stack.
37 static AtomicStack* Create(const std::string& name, size_t capacity) {
38 UniquePtr<AtomicStack> mark_stack(new AtomicStack(name, capacity));
39 mark_stack->Init();
40 return mark_stack.release();
41 }
42
Ian Rogers1d54e732013-05-02 21:10:01 -070043 ~AtomicStack() {}
Mathieu Chartierd8195f12012-10-05 12:21:28 -070044
45 void Reset() {
46 DCHECK(mem_map_.get() != NULL);
47 DCHECK(begin_ != NULL);
48 front_index_ = 0;
49 back_index_ = 0;
Mathieu Chartierf082d3c2013-07-29 17:04:07 -070050 debug_is_sorted_ = true;
Mathieu Chartierd8195f12012-10-05 12:21:28 -070051 int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED);
52 if (result == -1) {
53 PLOG(WARNING) << "madvise failed";
54 }
55 }
56
57 // Beware: Mixing atomic pushes and atomic pops will cause ABA problem.
58
59 // Returns false if we overflowed the stack.
60 bool AtomicPushBack(const T& value) {
Mathieu Chartierf082d3c2013-07-29 17:04:07 -070061 if (kIsDebugBuild) {
62 debug_is_sorted_ = false;
63 }
Ian Rogers56edc432013-01-18 16:51:51 -080064 int32_t index;
65 do {
66 index = back_index_;
67 if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
68 // Stack overflow.
69 return false;
70 }
Ian Rogersb122a4b2013-11-19 18:00:50 -080071 } while (!back_index_.CompareAndSwap(index, index + 1));
Mathieu Chartierd8195f12012-10-05 12:21:28 -070072 begin_[index] = value;
73 return true;
74 }
75
76 void PushBack(const T& value) {
Mathieu Chartierf082d3c2013-07-29 17:04:07 -070077 if (kIsDebugBuild) {
78 debug_is_sorted_ = false;
79 }
Mathieu Chartierd8195f12012-10-05 12:21:28 -070080 int32_t index = back_index_;
81 DCHECK_LT(static_cast<size_t>(index), capacity_);
82 back_index_ = index + 1;
83 begin_[index] = value;
84 }
85
86 T PopBack() {
87 DCHECK_GT(back_index_, front_index_);
88 // Decrement the back index non atomically.
89 back_index_ = back_index_ - 1;
90 return begin_[back_index_];
91 }
92
Mathieu Chartierd8195f12012-10-05 12:21:28 -070093 // Take an item from the front of the stack.
94 T PopFront() {
95 int32_t index = front_index_;
Ian Rogersb122a4b2013-11-19 18:00:50 -080096 DCHECK_LT(index, back_index_.Load());
Mathieu Chartierd8195f12012-10-05 12:21:28 -070097 front_index_ = front_index_ + 1;
98 return begin_[index];
99 }
100
Mathieu Chartier94c32c52013-08-09 11:14:04 -0700101 // Pop a number of elements.
102 void PopBackCount(int32_t n) {
103 DCHECK_GE(Size(), static_cast<size_t>(n));
Ian Rogersb122a4b2013-11-19 18:00:50 -0800104 back_index_.FetchAndSub(n);
Mathieu Chartier94c32c52013-08-09 11:14:04 -0700105 }
106
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700107 bool IsEmpty() const {
108 return Size() == 0;
109 }
110
111 size_t Size() const {
112 DCHECK_LE(front_index_, back_index_);
113 return back_index_ - front_index_;
114 }
115
Ian Rogers1d54e732013-05-02 21:10:01 -0700116 T* Begin() const {
Mathieu Chartier94c32c52013-08-09 11:14:04 -0700117 return const_cast<T*>(begin_ + front_index_);
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700118 }
119
Ian Rogers1d54e732013-05-02 21:10:01 -0700120 T* End() const {
Mathieu Chartier94c32c52013-08-09 11:14:04 -0700121 return const_cast<T*>(begin_ + back_index_);
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700122 }
123
124 size_t Capacity() const {
125 return capacity_;
126 }
127
128 // Will clear the stack.
129 void Resize(size_t new_capacity) {
130 capacity_ = new_capacity;
131 Init();
132 }
133
Ian Rogers1d54e732013-05-02 21:10:01 -0700134 void Sort() {
Ian Rogersb122a4b2013-11-19 18:00:50 -0800135 int32_t start_back_index = back_index_.Load();
136 int32_t start_front_index = front_index_.Load();
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700137 std::sort(Begin(), End());
Ian Rogersb122a4b2013-11-19 18:00:50 -0800138 CHECK_EQ(start_back_index, back_index_.Load());
139 CHECK_EQ(start_front_index, front_index_.Load());
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700140 if (kIsDebugBuild) {
141 debug_is_sorted_ = true;
Ian Rogers1d54e732013-05-02 21:10:01 -0700142 }
143 }
144
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700145 bool ContainsSorted(const T& value) const {
146 DCHECK(debug_is_sorted_);
147 return std::binary_search(Begin(), End(), value);
148 }
149
Ian Rogers1d54e732013-05-02 21:10:01 -0700150 bool Contains(const T& value) const {
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700151 return std::find(Begin(), End(), value) != End();
Ian Rogers1d54e732013-05-02 21:10:01 -0700152 }
153
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700154 private:
155 AtomicStack(const std::string& name, const size_t capacity)
156 : name_(name),
157 back_index_(0),
158 front_index_(0),
159 begin_(NULL),
Ian Rogers1d54e732013-05-02 21:10:01 -0700160 capacity_(capacity),
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700161 debug_is_sorted_(true) {
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700162 }
163
164 // Size in number of elements.
165 void Init() {
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700166 std::string error_msg;
167 mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T),
Ian Rogersef7d42f2014-01-06 12:55:46 -0800168 PROT_READ | PROT_WRITE, false, &error_msg));
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700169 CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg;
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700170 byte* addr = mem_map_->Begin();
171 CHECK(addr != NULL);
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700172 debug_is_sorted_ = true;
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700173 begin_ = reinterpret_cast<T*>(addr);
174 Reset();
175 }
176
177 // Name of the mark stack.
178 std::string name_;
179
180 // Memory mapping of the atomic stack.
181 UniquePtr<MemMap> mem_map_;
182
183 // Back index (index after the last element pushed).
184 AtomicInteger back_index_;
185
186 // Front index, used for implementing PopFront.
187 AtomicInteger front_index_;
188
189 // Base of the atomic stack.
190 T* begin_;
191
192 // Maximum number of elements.
193 size_t capacity_;
194
Mathieu Chartierf082d3c2013-07-29 17:04:07 -0700195 // Whether or not the stack is sorted, only updated in debug mode to avoid performance overhead.
196 bool debug_is_sorted_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700197
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700198 DISALLOW_COPY_AND_ASSIGN(AtomicStack);
199};
200
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800201typedef AtomicStack<mirror::Object*> ObjectStack;
202
Ian Rogers1d54e732013-05-02 21:10:01 -0700203} // namespace accounting
204} // namespace gc
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700205} // namespace art
206
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700207#endif // ART_RUNTIME_GC_ACCOUNTING_ATOMIC_STACK_H_