1 /*
2 * Copyright (C) 2017 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 <pthread.h>
18
19 #include <cstdio>
20 #include <iostream>
21 #include <vector>
22
23 #include "android-base/logging.h"
24 #include "jni.h"
25 #include "jvmti.h"
26
27 #include "scoped_local_ref.h"
28 #include "scoped_primitive_array.h"
29
30 // Test infrastructure
31 #include "jvmti_helper.h"
32 #include "test_env.h"
33
34 namespace art {
35 namespace Test1934SignalThreads {
36
37 struct NativeMonitor {
38 jrawMonitorID continue_monitor;
39 bool should_continue;
40 jrawMonitorID start_monitor;
41 bool should_start;
42 };
43
Java_art_Test1934_allocNativeMonitor(JNIEnv * env,jclass)44 extern "C" JNIEXPORT jlong JNICALL Java_art_Test1934_allocNativeMonitor(JNIEnv* env, jclass) {
45 NativeMonitor* mon;
46 if (JvmtiErrorToException(env,
47 jvmti_env,
48 jvmti_env->Allocate(sizeof(NativeMonitor),
49 reinterpret_cast<unsigned char**>(&mon)))) {
50 return -1L;
51 }
52 if (JvmtiErrorToException(env,
53 jvmti_env,
54 jvmti_env->CreateRawMonitor("test-1934 start",
55 &mon->start_monitor))) {
56 return -1L;
57 }
58 if (JvmtiErrorToException(env,
59 jvmti_env,
60 jvmti_env->CreateRawMonitor("test-1934 continue",
61 &mon->continue_monitor))) {
62 return -1L;
63 }
64 mon->should_continue = false;
65 mon->should_start = false;
66 return static_cast<jlong>(reinterpret_cast<intptr_t>(mon));
67 }
68
Java_art_Test1934_nativeWaitForOtherThread(JNIEnv * env,jclass,jlong id)69 extern "C" JNIEXPORT void Java_art_Test1934_nativeWaitForOtherThread(JNIEnv* env,
70 jclass,
71 jlong id) {
72 NativeMonitor* mon = reinterpret_cast<NativeMonitor*>(static_cast<intptr_t>(id));
73 // Start
74 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon->start_monitor))) {
75 return;
76 }
77 mon->should_start = true;
78 if (JvmtiErrorToException(env,
79 jvmti_env,
80 jvmti_env->RawMonitorNotifyAll(mon->start_monitor))) {
81 JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->start_monitor));
82 return;
83 }
84 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->start_monitor))) {
85 return;
86 }
87
88 // Finish
89 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon->continue_monitor))) {
90 return;
91 }
92 while (!mon->should_continue) {
93 if (JvmtiErrorToException(env,
94 jvmti_env,
95 jvmti_env->RawMonitorWait(mon->continue_monitor, -1L))) {
96 JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->continue_monitor));
97 return;
98 }
99 }
100 JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->continue_monitor));
101 }
102
Java_art_Test1934_nativeDoInterleaved(JNIEnv * env,jclass,jlong id,jobject closure)103 extern "C" JNIEXPORT void Java_art_Test1934_nativeDoInterleaved(JNIEnv* env,
104 jclass,
105 jlong id,
106 jobject closure) {
107 NativeMonitor* mon = reinterpret_cast<NativeMonitor*>(static_cast<intptr_t>(id));
108 // Wait for start.
109 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon->start_monitor))) {
110 return;
111 }
112 while (!mon->should_start) {
113 if (JvmtiErrorToException(env,
114 jvmti_env,
115 jvmti_env->RawMonitorWait(mon->start_monitor, -1L))) {
116 return;
117 }
118 }
119 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->start_monitor))) {
120 return;
121 }
122
123 // Call closure.
124 ScopedLocalRef<jclass> runnable_klass(env, env->FindClass("java/lang/Runnable"));
125 if (env->ExceptionCheck()) {
126 return;
127 }
128 jmethodID doRun = env->GetMethodID(runnable_klass.get(), "run", "()V");
129 if (env->ExceptionCheck()) {
130 return;
131 }
132 env->CallVoidMethod(closure, doRun);
133
134 // Tell other thread to finish.
135 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon->continue_monitor))) {
136 return;
137 }
138 mon->should_continue = true;
139 if (JvmtiErrorToException(env,
140 jvmti_env,
141 jvmti_env->RawMonitorNotifyAll(mon->continue_monitor))) {
142 JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->continue_monitor));
143 return;
144 }
145 JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon->continue_monitor));
146 }
147
Java_art_Test1934_destroyNativeMonitor(JNIEnv *,jclass,jlong id)148 extern "C" JNIEXPORT void Java_art_Test1934_destroyNativeMonitor(JNIEnv*, jclass, jlong id) {
149 NativeMonitor* mon = reinterpret_cast<NativeMonitor*>(static_cast<intptr_t>(id));
150 jvmti_env->DestroyRawMonitor(mon->start_monitor);
151 jvmti_env->DestroyRawMonitor(mon->continue_monitor);
152 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(mon));
153 }
154
155 } // namespace Test1934SignalThreads
156 } // namespace art
157
158