/** * 关闭Jit编译器 */ void dvmCompilerShutdown(void) { void *threadReturn; /* Disable new translation requests */ /* 关闭新的编译请求 */ gDvmJit.pProfTable = NULL; gDvmJit.pProfTableCopy = NULL; dvmJitUpdateThreadStateAll(); /* 更新所有线程状态 */ /* * 以下代码应该是检测在虚拟机关闭之前等待所有编译工作队列完成 * dvmCompilerDumpStats()函数应该会更新所有工作队列的当前状态 * gDvmJit.compilerQueueLength会随着这个函数进行更新,这个常数 * 即是当前工作队列的数量。 */ if (gDvm.verboseShutdown || gDvmJit.profileMode == kTraceProfilingContinuous) { dvmCompilerDumpStats(); while (gDvmJit.compilerQueueLength) sleep(5); } /* 如果编译器工作线程存在 */ if (gDvmJit.compilerHandle) { gDvmJit.haltCompilerThread = true; /* 设置关闭标志为true */ /* 发送关闭信号 */ dvmLockMutex(&gDvmJit.compilerLock); pthread_cond_signal(&gDvmJit.compilerQueueActivity); dvmUnlockMutex(&gDvmJit.compilerLock); /* 关闭compilerThreadStart线程 */ if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0) ALOGW("Compiler thread join failed"); else if (gDvm.verboseShutdown) ALOGD("Compiler thread has shut down"); } /* Break loops within the translation cache */ dvmJitUnchainAll(); /* * NOTE: our current implementatation doesn't allow for the compiler * thread to be restarted after it exits here. We aren't freeing * the JitTable or the ProfTable because threads which still may be * running or in the process of shutting down may hold references to * * them. */ }
/* * Respond to a SIGUSR2 by dumping some JIT stats and possibly resetting * the code cache. */ static void handleSigUsr2() { static int codeCacheResetCount = 0; gDvmJit.receivedSIGUSR2 ^= true; if ((--codeCacheResetCount & 7) == 0) { /* Dump all class pointers in the traces */ dvmJitScanAllClassPointers(printAllClass); gDvmJit.codeCacheFull = true; } else { dvmCompilerDumpStats(); /* Stress-test unchain all */ dvmJitUnchainAll(); ALOGD("Send %d more signals to reset the code cache", codeCacheResetCount & 7); } dvmCheckInterpStateConsistency(); }
/* * private static void nativeExit(int code, boolean isExit) * * Runtime.exit() calls this after doing shutdown processing. Runtime.halt() * uses this as well. */ static void Dalvik_java_lang_Runtime_nativeExit(const u4* args, JValue* pResult) { int status = args[0]; bool isExit = (args[1] != 0); if (isExit && gDvm.exitHook != NULL) { dvmChangeStatus(NULL, THREAD_NATIVE); (*gDvm.exitHook)(status); // not expected to return dvmChangeStatus(NULL, THREAD_RUNNING); LOGW("JNI exit hook returned\n"); } LOGD("Calling exit(%d)\n", status); #if defined(WITH_JIT) && defined(WITH_JIT_TUNING) dvmCompilerDumpStats(); #endif exit(status); }
void dvmCompilerShutdown(void) { void *threadReturn; /* Disable new translation requests */ gDvmJit.pProfTable = NULL; gDvmJit.pProfTableCopy = NULL; dvmJitUpdateThreadStateAll(); if (gDvm.verboseShutdown || gDvmJit.profileMode == kTraceProfilingContinuous) { dvmCompilerDumpStats(); while (gDvmJit.compilerQueueLength) sleep(5); } if (gDvmJit.compilerHandle) { gDvmJit.haltCompilerThread = true; dvmLockMutex(&gDvmJit.compilerLock); pthread_cond_signal(&gDvmJit.compilerQueueActivity); dvmUnlockMutex(&gDvmJit.compilerLock); if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0) ALOGW("Compiler thread join failed"); else if (gDvm.verboseShutdown) ALOGD("Compiler thread has shut down"); } /* Break loops within the translation cache */ dvmJitUnchainAll(); /* * NOTE: our current implementatation doesn't allow for the compiler * thread to be restarted after it exits here. We aren't freeing * the JitTable or the ProfTable because threads which still may be * running or in the process of shutting down may hold references to * them. */ }
/* * Respond to a SIGQUIT by dumping the thread stacks. Optionally dump * a few other things while we're at it. * * Thread stacks can either go to the log or to a file designated for holding * ANR traces. If we're writing to a file, we want to do it in one shot, * so we can use a single O_APPEND write instead of contending for exclusive * access with flock(). There may be an advantage in resuming the VM * before doing the file write, so we don't stall the VM if disk I/O is * bottlenecked. * * If JIT tuning is compiled in, dump compiler stats as well. */ static void handleSigQuit() { char* traceBuf = NULL; size_t traceLen; dvmSuspendAllThreads(SUSPEND_FOR_STACK_DUMP); dvmDumpLoaderStats("sig"); if (gDvm.stackTraceFile == NULL) { /* just dump to log */ DebugOutputTarget target; dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG); dvmDumpJniStats(&target); dvmDumpAllThreadsEx(&target, true); } else { /* write to memory buffer */ FILE* memfp = open_memstream(&traceBuf, &traceLen); if (memfp == NULL) { ALOGE("Unable to create memstream for stack traces"); traceBuf = NULL; /* make sure it didn't touch this */ /* continue on */ } else { logThreadStacks(memfp); fclose(memfp); } } #if defined(WITH_JIT) && defined(WITH_JIT_TUNING) dvmCompilerDumpStats(); #endif if (false) dvmDumpTrackedAllocations(true); dvmResumeAllThreads(SUSPEND_FOR_STACK_DUMP); if (traceBuf != NULL) { /* * We don't know how long it will take to do the disk I/O, so put us * into VMWAIT for the duration. */ ThreadStatus oldStatus = dvmChangeStatus(dvmThreadSelf(), THREAD_VMWAIT); /* * Open the stack trace output file, creating it if necessary. It * needs to be world-writable so other processes can write to it. */ int fd = open(gDvm.stackTraceFile, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) { ALOGE("Unable to open stack trace file '%s': %s", gDvm.stackTraceFile, strerror(errno)); } else { ssize_t actual = write(fd, traceBuf, traceLen); if (actual != (ssize_t) traceLen) { ALOGE("Failed to write stack traces to %s (%d of %zd): %s", gDvm.stackTraceFile, (int) actual, traceLen, strerror(errno)); } else { ALOGI("Wrote stack traces to '%s'", gDvm.stackTraceFile); } close(fd); } free(traceBuf); dvmChangeStatus(dvmThreadSelf(), oldStatus); } }