blob: 4a7920e080a6f14cd5ec21aa22f8e5afe3184cbe [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
17#ifndef ART_SRC_ATOMIC_STACK_H_
18#define ART_SRC_ATOMIC_STACK_H_
19
20#include <string>
21
22#include "atomic_integer.h"
Elliott Hughes76160052012-12-12 16:31:20 -080023#include "base/macros.h"
Mathieu Chartierd8195f12012-10-05 12:21:28 -070024#include "UniquePtr.h"
25#include "logging.h"
Mathieu Chartierd8195f12012-10-05 12:21:28 -070026#include "mem_map.h"
27#include "utils.h"
28
29namespace art {
30
31template <typename T>
32class AtomicStack {
33 public:
34 // Capacity is how many elements we can store in the stack.
35 static AtomicStack* Create(const std::string& name, size_t capacity) {
36 UniquePtr<AtomicStack> mark_stack(new AtomicStack(name, capacity));
37 mark_stack->Init();
38 return mark_stack.release();
39 }
40
41 ~AtomicStack(){
42
43 }
44
45 void Reset() {
46 DCHECK(mem_map_.get() != NULL);
47 DCHECK(begin_ != NULL);
48 front_index_ = 0;
49 back_index_ = 0;
50 int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED);
51 if (result == -1) {
52 PLOG(WARNING) << "madvise failed";
53 }
54 }
55
56 // Beware: Mixing atomic pushes and atomic pops will cause ABA problem.
57
58 // Returns false if we overflowed the stack.
59 bool AtomicPushBack(const T& value) {
60 const int32_t index = back_index_++;
61 if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
62 // Stack overflow.
63 back_index_--;
64 return false;
65 }
66 begin_[index] = value;
67 return true;
68 }
69
70 void PushBack(const T& value) {
71 int32_t index = back_index_;
72 DCHECK_LT(static_cast<size_t>(index), capacity_);
73 back_index_ = index + 1;
74 begin_[index] = value;
75 }
76
77 T PopBack() {
78 DCHECK_GT(back_index_, front_index_);
79 // Decrement the back index non atomically.
80 back_index_ = back_index_ - 1;
81 return begin_[back_index_];
82 }
83
84 T AtomicPopBack() {
85 // Decrement the back index non atomically.
86 int back_index = back_index_--;
87 DCHECK_GT(back_index, front_index_);
88 return begin_[back_index - 1];
89 }
90
91 // Take an item from the front of the stack.
92 T PopFront() {
93 int32_t index = front_index_;
94 DCHECK_LT(index, back_index_.get());
95 front_index_ = front_index_ + 1;
96 return begin_[index];
97 }
98
99 bool IsEmpty() const {
100 return Size() == 0;
101 }
102
103 size_t Size() const {
104 DCHECK_LE(front_index_, back_index_);
105 return back_index_ - front_index_;
106 }
107
108 T* Begin() {
109 return const_cast<Object**>(begin_ + front_index_);
110 }
111
112 T* End() {
113 return const_cast<Object**>(begin_ + back_index_);
114 }
115
116 size_t Capacity() const {
117 return capacity_;
118 }
119
120 // Will clear the stack.
121 void Resize(size_t new_capacity) {
122 capacity_ = new_capacity;
123 Init();
124 }
125
126 private:
127 AtomicStack(const std::string& name, const size_t capacity)
128 : name_(name),
129 back_index_(0),
130 front_index_(0),
131 begin_(NULL),
132 capacity_(capacity) {
133
134 }
135
136 // Size in number of elements.
137 void Init() {
138 mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE));
jeffhao8161c032012-10-31 15:50:00 -0700139 CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack";
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700140 byte* addr = mem_map_->Begin();
141 CHECK(addr != NULL);
142 begin_ = reinterpret_cast<T*>(addr);
143 Reset();
144 }
145
146 // Name of the mark stack.
147 std::string name_;
148
149 // Memory mapping of the atomic stack.
150 UniquePtr<MemMap> mem_map_;
151
152 // Back index (index after the last element pushed).
153 AtomicInteger back_index_;
154
155 // Front index, used for implementing PopFront.
156 AtomicInteger front_index_;
157
158 // Base of the atomic stack.
159 T* begin_;
160
161 // Maximum number of elements.
162 size_t capacity_;
163
164 DISALLOW_COPY_AND_ASSIGN(AtomicStack);
165};
166
167} // namespace art
168
169#endif // ART_SRC_MARK_STACK_H_