xref: /aosp_15_r20/art/runtime/monitor_pool.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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