1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "monitor_pool.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "base/logging.h" // For VLOG.
20*795d594fSAndroid Build Coastguard Worker #include "base/mutex-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "monitor.h"
22*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker namespace mirror {
27*795d594fSAndroid Build Coastguard Worker class Object;
28*795d594fSAndroid Build Coastguard Worker } // namespace mirror
29*795d594fSAndroid Build Coastguard Worker
MonitorPool()30*795d594fSAndroid Build Coastguard Worker MonitorPool::MonitorPool()
31*795d594fSAndroid Build Coastguard Worker : current_chunk_list_index_(0), num_chunks_(0), current_chunk_list_capacity_(0),
32*795d594fSAndroid Build Coastguard Worker first_free_(nullptr) {
33*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kMaxChunkLists; ++i) {
34*795d594fSAndroid Build Coastguard Worker monitor_chunks_[i] = nullptr; // Not absolutely required, but ...
35*795d594fSAndroid Build Coastguard Worker }
36*795d594fSAndroid Build Coastguard Worker AllocateChunk(); // Get our first chunk.
37*795d594fSAndroid Build Coastguard Worker }
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Worker // Assumes locks are held appropriately when necessary.
40*795d594fSAndroid Build Coastguard Worker // We do not need a lock in the constructor, but we need one when in CreateMonitorInPool.
AllocateChunk()41*795d594fSAndroid Build Coastguard Worker void MonitorPool::AllocateChunk() {
42*795d594fSAndroid Build Coastguard Worker DCHECK(first_free_ == nullptr);
43*795d594fSAndroid Build Coastguard Worker
44*795d594fSAndroid Build Coastguard Worker // Do we need to allocate another chunk list?
45*795d594fSAndroid Build Coastguard Worker if (num_chunks_ == current_chunk_list_capacity_) {
46*795d594fSAndroid Build Coastguard Worker if (current_chunk_list_capacity_ != 0U) {
47*795d594fSAndroid Build Coastguard Worker ++current_chunk_list_index_;
48*795d594fSAndroid Build Coastguard Worker CHECK_LT(current_chunk_list_index_, kMaxChunkLists) << "Out of space for inflated monitors";
49*795d594fSAndroid Build Coastguard Worker VLOG(monitor) << "Expanding to capacity "
50*795d594fSAndroid Build Coastguard Worker << 2 * ChunkListCapacity(current_chunk_list_index_) - kInitialChunkStorage;
51*795d594fSAndroid Build Coastguard Worker } // else we're initializing
52*795d594fSAndroid Build Coastguard Worker current_chunk_list_capacity_ = ChunkListCapacity(current_chunk_list_index_);
53*795d594fSAndroid Build Coastguard Worker uintptr_t* new_list = new uintptr_t[current_chunk_list_capacity_]();
54*795d594fSAndroid Build Coastguard Worker DCHECK(monitor_chunks_[current_chunk_list_index_] == nullptr);
55*795d594fSAndroid Build Coastguard Worker monitor_chunks_[current_chunk_list_index_] = new_list;
56*795d594fSAndroid Build Coastguard Worker num_chunks_ = 0;
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker // Allocate the chunk.
60*795d594fSAndroid Build Coastguard Worker void* chunk = allocator_.allocate(kChunkSize);
61*795d594fSAndroid Build Coastguard Worker // Check we allocated memory.
62*795d594fSAndroid Build Coastguard Worker CHECK_NE(reinterpret_cast<uintptr_t>(nullptr), reinterpret_cast<uintptr_t>(chunk));
63*795d594fSAndroid Build Coastguard Worker // Check it is aligned as we need it.
64*795d594fSAndroid Build Coastguard Worker CHECK_EQ(0U, reinterpret_cast<uintptr_t>(chunk) % kMonitorAlignment);
65*795d594fSAndroid Build Coastguard Worker
66*795d594fSAndroid Build Coastguard Worker // Add the chunk.
67*795d594fSAndroid Build Coastguard Worker monitor_chunks_[current_chunk_list_index_][num_chunks_] = reinterpret_cast<uintptr_t>(chunk);
68*795d594fSAndroid Build Coastguard Worker num_chunks_++;
69*795d594fSAndroid Build Coastguard Worker
70*795d594fSAndroid Build Coastguard Worker // Set up the free list
71*795d594fSAndroid Build Coastguard Worker Monitor* last = reinterpret_cast<Monitor*>(reinterpret_cast<uintptr_t>(chunk) +
72*795d594fSAndroid Build Coastguard Worker (kChunkCapacity - 1) * kAlignedMonitorSize);
73*795d594fSAndroid Build Coastguard Worker last->next_free_ = nullptr;
74*795d594fSAndroid Build Coastguard Worker // Eagerly compute id.
75*795d594fSAndroid Build Coastguard Worker last->monitor_id_ = OffsetToMonitorId(current_chunk_list_index_* (kMaxListSize * kChunkSize)
76*795d594fSAndroid Build Coastguard Worker + (num_chunks_ - 1) * kChunkSize + (kChunkCapacity - 1) * kAlignedMonitorSize);
77*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < kChunkCapacity - 1; ++i) {
78*795d594fSAndroid Build Coastguard Worker Monitor* before = reinterpret_cast<Monitor*>(reinterpret_cast<uintptr_t>(last) -
79*795d594fSAndroid Build Coastguard Worker kAlignedMonitorSize);
80*795d594fSAndroid Build Coastguard Worker before->next_free_ = last;
81*795d594fSAndroid Build Coastguard Worker // Derive monitor_id from last.
82*795d594fSAndroid Build Coastguard Worker before->monitor_id_ = OffsetToMonitorId(MonitorIdToOffset(last->monitor_id_) -
83*795d594fSAndroid Build Coastguard Worker kAlignedMonitorSize);
84*795d594fSAndroid Build Coastguard Worker
85*795d594fSAndroid Build Coastguard Worker last = before;
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker DCHECK(last == reinterpret_cast<Monitor*>(chunk));
88*795d594fSAndroid Build Coastguard Worker first_free_ = last;
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker
FreeInternal()91*795d594fSAndroid Build Coastguard Worker void MonitorPool::FreeInternal() {
92*795d594fSAndroid Build Coastguard Worker // This is on shutdown with NO_THREAD_SAFETY_ANALYSIS, can't/don't need to lock.
93*795d594fSAndroid Build Coastguard Worker DCHECK_NE(current_chunk_list_capacity_, 0UL);
94*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i <= current_chunk_list_index_; ++i) {
95*795d594fSAndroid Build Coastguard Worker DCHECK_NE(monitor_chunks_[i], static_cast<uintptr_t*>(nullptr));
96*795d594fSAndroid Build Coastguard Worker for (size_t j = 0; j < ChunkListCapacity(i); ++j) {
97*795d594fSAndroid Build Coastguard Worker if (i < current_chunk_list_index_ || j < num_chunks_) {
98*795d594fSAndroid Build Coastguard Worker DCHECK_NE(monitor_chunks_[i][j], 0U);
99*795d594fSAndroid Build Coastguard Worker allocator_.deallocate(reinterpret_cast<uint8_t*>(monitor_chunks_[i][j]), kChunkSize);
100*795d594fSAndroid Build Coastguard Worker } else {
101*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(monitor_chunks_[i][j], 0U);
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker }
104*795d594fSAndroid Build Coastguard Worker delete[] monitor_chunks_[i];
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker }
107*795d594fSAndroid Build Coastguard Worker
CreateMonitorInPool(Thread * self,Thread * owner,ObjPtr<mirror::Object> obj,int32_t hash_code)108*795d594fSAndroid Build Coastguard Worker Monitor* MonitorPool::CreateMonitorInPool(Thread* self,
109*795d594fSAndroid Build Coastguard Worker Thread* owner,
110*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> obj,
111*795d594fSAndroid Build Coastguard Worker int32_t hash_code)
112*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
113*795d594fSAndroid Build Coastguard Worker // We are gonna allocate, so acquire the writer lock.
114*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker // Enough space, or need to resize?
117*795d594fSAndroid Build Coastguard Worker if (first_free_ == nullptr) {
118*795d594fSAndroid Build Coastguard Worker VLOG(monitor) << "Allocating a new chunk.";
119*795d594fSAndroid Build Coastguard Worker AllocateChunk();
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker Monitor* mon_uninitialized = first_free_;
123*795d594fSAndroid Build Coastguard Worker first_free_ = first_free_->next_free_;
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker // Pull out the id which was preinitialized.
126*795d594fSAndroid Build Coastguard Worker MonitorId id = mon_uninitialized->monitor_id_;
127*795d594fSAndroid Build Coastguard Worker
128*795d594fSAndroid Build Coastguard Worker // Initialize it.
129*795d594fSAndroid Build Coastguard Worker Monitor* monitor = new(mon_uninitialized) Monitor(self, owner, obj, hash_code, id);
130*795d594fSAndroid Build Coastguard Worker
131*795d594fSAndroid Build Coastguard Worker return monitor;
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker
ReleaseMonitorToPool(Thread * self,Monitor * monitor)134*795d594fSAndroid Build Coastguard Worker void MonitorPool::ReleaseMonitorToPool(Thread* self, Monitor* monitor) {
135*795d594fSAndroid Build Coastguard Worker // Might be racy with allocation, so acquire lock.
136*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker // Keep the monitor id. Don't trust it's not cleared.
139*795d594fSAndroid Build Coastguard Worker MonitorId id = monitor->monitor_id_;
140*795d594fSAndroid Build Coastguard Worker
141*795d594fSAndroid Build Coastguard Worker // Call the destructor.
142*795d594fSAndroid Build Coastguard Worker // TODO: Exception safety?
143*795d594fSAndroid Build Coastguard Worker monitor->~Monitor();
144*795d594fSAndroid Build Coastguard Worker
145*795d594fSAndroid Build Coastguard Worker // Add to the head of the free list.
146*795d594fSAndroid Build Coastguard Worker monitor->next_free_ = first_free_;
147*795d594fSAndroid Build Coastguard Worker first_free_ = monitor;
148*795d594fSAndroid Build Coastguard Worker
149*795d594fSAndroid Build Coastguard Worker // Rewrite monitor id.
150*795d594fSAndroid Build Coastguard Worker monitor->monitor_id_ = id;
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker
ReleaseMonitorsToPool(Thread * self,MonitorList::Monitors * monitors)153*795d594fSAndroid Build Coastguard Worker void MonitorPool::ReleaseMonitorsToPool(Thread* self, MonitorList::Monitors* monitors) {
154*795d594fSAndroid Build Coastguard Worker for (Monitor* mon : *monitors) {
155*795d594fSAndroid Build Coastguard Worker ReleaseMonitorToPool(self, mon);
156*795d594fSAndroid Build Coastguard Worker }
157*795d594fSAndroid Build Coastguard Worker }
158*795d594fSAndroid Build Coastguard Worker
159*795d594fSAndroid Build Coastguard Worker } // namespace art
160