1 /*
2 * Copyright (C) 2011 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 #include "lock_count_data.h"
18
19 #include <algorithm>
20 #include <string>
21
22 #include "android-base/logging.h"
23 #include "mirror/object-inl.h"
24 #include "thread.h"
25
26 namespace art {
27
AddMonitor(Thread * self,mirror::Object * obj)28 void LockCountData::AddMonitor(Thread* self, mirror::Object* obj) {
29 if (obj == nullptr) {
30 return;
31 }
32
33 // If there's an error during enter, we won't have locked the monitor. So check there's no
34 // exception.
35 if (self->IsExceptionPending()) {
36 return;
37 }
38
39 if (monitors_ == nullptr) {
40 monitors_.reset(new std::vector<mirror::Object*>());
41 }
42 monitors_->push_back(obj);
43 }
44
RemoveMonitorOrThrow(Thread * self,const mirror::Object * obj)45 void LockCountData::RemoveMonitorOrThrow(Thread* self, const mirror::Object* obj) {
46 if (obj == nullptr) {
47 return;
48 }
49 bool found_object = false;
50 if (monitors_ != nullptr) {
51 // We need to remove one pointer to ref, as duplicates are used for counting recursive locks.
52 // We arbitrarily choose the first one.
53 auto it = std::find(monitors_->begin(), monitors_->end(), obj);
54 if (it != monitors_->end()) {
55 monitors_->erase(it);
56 found_object = true;
57 }
58 }
59 if (!found_object) {
60 // The object wasn't found. Time for an IllegalMonitorStateException.
61 // The order here isn't fully clear. Assume that any other pending exception is swallowed.
62 // TODO: Maybe make already pending exception a suppressed exception.
63 self->ClearException();
64 self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;",
65 "did not lock monitor on object of type '%s' before unlocking",
66 const_cast<mirror::Object*>(obj)->PrettyTypeOf().c_str());
67 }
68 }
69
70 // Helper to unlock a monitor. Must be NO_THREAD_SAFETY_ANALYSIS, as we can't statically show
71 // that the object was locked.
MonitorExitHelper(Thread * self,mirror::Object * obj)72 void MonitorExitHelper(Thread* self, mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS {
73 DCHECK(self != nullptr);
74 DCHECK(obj != nullptr);
75 obj->MonitorExit(self);
76 }
77
CheckAllMonitorsReleasedOrThrow(Thread * self)78 bool LockCountData::CheckAllMonitorsReleasedOrThrow(Thread* self) {
79 DCHECK(self != nullptr);
80 if (monitors_ != nullptr) {
81 if (!monitors_->empty()) {
82 // There may be an exception pending, if the method is terminating abruptly. Clear it.
83 // TODO: Should we add this as a suppressed exception?
84 self->ClearException();
85
86 // OK, there are monitors that are still locked. To enforce structured locking (and avoid
87 // deadlocks) we unlock all of them before we raise the IllegalMonitorState exception.
88 for (mirror::Object* obj : *monitors_) {
89 MonitorExitHelper(self, obj);
90 // If this raised an exception, ignore. TODO: Should we add this as suppressed
91 // exceptions?
92 if (self->IsExceptionPending()) {
93 self->ClearException();
94 }
95 }
96 // Raise an exception, just give the first object as the sample.
97 mirror::Object* first = (*monitors_)[0];
98 self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;",
99 "did not unlock monitor on object of type '%s'",
100 mirror::Object::PrettyTypeOf(first).c_str());
101
102 // To make sure this path is not triggered again, clean out the monitors.
103 monitors_->clear();
104
105 return false;
106 }
107 }
108 return true;
109 }
110
111 } // namespace art
112