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