blob: 0197bce992582ac66d8a717910773fe812d28687 [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 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 {
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) {
Ian Rogers56edc432013-01-18 16:51:51 -080060 int32_t index;
61 do {
62 index = back_index_;
63 if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
64 // Stack overflow.
65 return false;
66 }
67 } while(!back_index_.CompareAndSwap(index, index + 1));
Mathieu Chartierd8195f12012-10-05 12:21:28 -070068 begin_[index] = value;
69 return true;
70 }
71
72 void PushBack(const T& value) {
73 int32_t index = back_index_;
74 DCHECK_LT(static_cast<size_t>(index), capacity_);
75 back_index_ = index + 1;
76 begin_[index] = value;
77 }
78
79 T PopBack() {
80 DCHECK_GT(back_index_, front_index_);
81 // Decrement the back index non atomically.
82 back_index_ = back_index_ - 1;
83 return begin_[back_index_];
84 }
85
Mathieu Chartierd8195f12012-10-05 12:21:28 -070086 // Take an item from the front of the stack.
87 T PopFront() {
88 int32_t index = front_index_;
89 DCHECK_LT(index, back_index_.get());
90 front_index_ = front_index_ + 1;
91 return begin_[index];
92 }
93
94 bool IsEmpty() const {
95 return Size() == 0;
96 }
97
98 size_t Size() const {
99 DCHECK_LE(front_index_, back_index_);
100 return back_index_ - front_index_;
101 }
102
103 T* Begin() {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800104 return const_cast<mirror::Object**>(begin_ + front_index_);
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700105 }
106
107 T* End() {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800108 return const_cast<mirror::Object**>(begin_ + back_index_);
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700109 }
110
111 size_t Capacity() const {
112 return capacity_;
113 }
114
115 // Will clear the stack.
116 void Resize(size_t new_capacity) {
117 capacity_ = new_capacity;
118 Init();
119 }
120
121 private:
122 AtomicStack(const std::string& name, const size_t capacity)
123 : name_(name),
124 back_index_(0),
125 front_index_(0),
126 begin_(NULL),
127 capacity_(capacity) {
128
129 }
130
131 // Size in number of elements.
132 void Init() {
133 mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE));
jeffhao8161c032012-10-31 15:50:00 -0700134 CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack";
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700135 byte* addr = mem_map_->Begin();
136 CHECK(addr != NULL);
137 begin_ = reinterpret_cast<T*>(addr);
138 Reset();
139 }
140
141 // Name of the mark stack.
142 std::string name_;
143
144 // Memory mapping of the atomic stack.
145 UniquePtr<MemMap> mem_map_;
146
147 // Back index (index after the last element pushed).
148 AtomicInteger back_index_;
149
150 // Front index, used for implementing PopFront.
151 AtomicInteger front_index_;
152
153 // Base of the atomic stack.
154 T* begin_;
155
156 // Maximum number of elements.
157 size_t capacity_;
158
159 DISALLOW_COPY_AND_ASSIGN(AtomicStack);
160};
161
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800162typedef AtomicStack<mirror::Object*> ObjectStack;
163
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700164} // namespace art
165
166#endif // ART_SRC_MARK_STACK_H_