blob: b7293015cfa91aba85dcc39de06261e7f7380e54 [file] [log] [blame]
Mathieu Chartierfc7acf92016-01-13 16:20:26 -08001/*
2 * Copyright (C) 2016 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
Mathieu Chartier06fd2cf2016-05-05 11:09:58 -070017#include <dlfcn.h>
Mathieu Chartierfc7acf92016-01-13 16:20:26 -080018#include <iostream>
19
20#include "base/casts.h"
21#include "base/macros.h"
22#include "java_vm_ext.h"
23#include "jni_env_ext.h"
24#include "thread-inl.h"
25
26namespace art {
27namespace {
28
29static volatile std::atomic<bool> vm_was_shutdown(false);
Alex Lightbc5669e2016-06-13 17:22:13 +000030static const int kThreadCount = 4;
31
32static std::atomic<int> barrier_count(kThreadCount + 1);
33
34static void JniThreadBarrierWait() {
35 barrier_count--;
36 while (barrier_count.load() != 0) {
37 usleep(1000);
38 }
39}
Mathieu Chartierfc7acf92016-01-13 16:20:26 -080040
41extern "C" JNIEXPORT void JNICALL Java_Main_waitAndCallIntoJniEnv(JNIEnv* env, jclass) {
Alex Lightbc5669e2016-06-13 17:22:13 +000042 // Wait for all threads to enter JNI together.
43 JniThreadBarrierWait();
Mathieu Chartierfc7acf92016-01-13 16:20:26 -080044 // Wait until the runtime is shutdown.
45 while (!vm_was_shutdown.load()) {
46 usleep(1000);
47 }
48 std::cout << "About to call exception check\n";
49 env->ExceptionCheck();
50 LOG(ERROR) << "Should not be reached!";
51}
52
53// NO_RETURN does not work with extern "C" for target builds.
54extern "C" JNIEXPORT void JNICALL Java_Main_destroyJavaVMAndExit(JNIEnv* env, jclass) {
Alex Lightbc5669e2016-06-13 17:22:13 +000055 // Wait for all threads to enter JNI together.
56 JniThreadBarrierWait();
Mathieu Chartierfc7acf92016-01-13 16:20:26 -080057 // Fake up the managed stack so we can detach.
58 Thread* const self = Thread::Current();
59 self->SetTopOfStack(nullptr);
60 self->SetTopOfShadowStack(nullptr);
61 JavaVM* vm = down_cast<JNIEnvExt*>(env)->vm;
62 vm->DetachCurrentThread();
Mathieu Chartier06fd2cf2016-05-05 11:09:58 -070063 // Open ourself again to make sure the native library does not get unloaded from
64 // underneath us due to DestroyJavaVM. b/28406866
Mathieu Chartier48b2b3e2016-05-05 15:31:12 -070065 void* handle = dlopen(kIsDebugBuild ? "libarttestd.so" : "libarttest.so", RTLD_NOW);
66 CHECK(handle != nullptr);
Mathieu Chartierfc7acf92016-01-13 16:20:26 -080067 vm->DestroyJavaVM();
68 vm_was_shutdown.store(true);
69 // Give threads some time to get stuck in ExceptionCheck.
70 usleep(1000000);
71 if (env != nullptr) {
72 // Use env != nullptr to trick noreturn.
73 exit(0);
74 }
75}
76
77} // namespace
78} // namespace art