Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_init.c
38829 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940/* Main source file, the basic JVMTI connection/startup code. */4142#include "hprof.h"4344#include "java_crw_demo.h"4546/*47* This file contains all the startup logic (Agent_Onload) and48* connection to the JVMTI interface.49* All JVMTI Event callbacks are in this file.50* All setting of global data (gdata) is done here.51* Options are parsed here.52* Option help messages are here.53* Termination handled here (VM_DEATH) and shutdown (Agent_OnUnload).54* Spawning of the cpu sample loop thread and listener thread is done here.55*56* Use of private 'static' data has been limited, most shared static data57* should be found in the GlobalData structure pointed to by gdata58* (see hprof.h).59*60*/6162/* The default output filenames. */6364#define DEFAULT_TXT_SUFFIX ".txt"65#define DEFAULT_OUTPUTFILE "java.hprof"66#define DEFAULT_OUTPUTTEMP "java.hprof.temp"6768/* The only global variable, defined by this library */69GlobalData *gdata;7071/* Experimental options */72#define EXPERIMENT_NO_EARLY_HOOK 0x17374/* Default trace depth */75#define DEFAULT_TRACE_DEPTH 47677/* Default sample interval */78#define DEFAULT_SAMPLE_INTERVAL 107980/* Default cutoff */81#define DEFAULT_CUTOFF_POINT 0.00018283/* Stringize macros for help. */84#define _TO_STR(a) #a85#define TO_STR(a) _TO_STR(a)8687/* Macros to surround callback code (non-VM_DEATH callbacks).88* Note that this just keeps a count of the non-VM_DEATH callbacks that89* are currently active, it does not prevent these callbacks from90* operating in parallel. It's the VM_DEATH callback that will wait91* for all these callbacks to either complete and block, or just block.92* We need to hold back these threads so they don't die during the final93* VM_DEATH processing.94* If the VM_DEATH callback is active in the beginning, then this callback95* just blocks to prevent further execution of the thread.96* If the VM_DEATH callback is active at the end, then this callback97* will notify the VM_DEATH callback if it's the last one.98* In all cases, the last thing they do is Enter/Exit the monitor99* gdata->callbackBlock, which will block this callback if VM_DEATH100* is running.101*102* WARNING: No not 'return' or 'goto' out of the BEGIN_CALLBACK/END_CALLBACK103* block, this will mess up the count.104*/105106#define BEGIN_CALLBACK() \107{ /* BEGIN OF CALLBACK */ \108jboolean bypass; \109rawMonitorEnter(gdata->callbackLock); \110if (gdata->vm_death_callback_active) { \111/* VM_DEATH is active, we will bypass the CALLBACK CODE */ \112bypass = JNI_TRUE; \113rawMonitorExit(gdata->callbackLock); \114/* Bypassed CALLBACKS block here until VM_DEATH done */ \115rawMonitorEnter(gdata->callbackBlock); \116rawMonitorExit(gdata->callbackBlock); \117} else { \118/* We will be executing the CALLBACK CODE in this case */ \119gdata->active_callbacks++; \120bypass = JNI_FALSE; \121rawMonitorExit(gdata->callbackLock); \122} \123if ( !bypass ) { \124/* BODY OF CALLBACK CODE (with no callback locks held) */125126#define END_CALLBACK() /* Part of bypass if body */ \127rawMonitorEnter(gdata->callbackLock); \128gdata->active_callbacks--; \129/* If VM_DEATH is active, and last one, send notify. */ \130if (gdata->vm_death_callback_active) { \131if (gdata->active_callbacks == 0) { \132rawMonitorNotifyAll(gdata->callbackLock); \133} \134} \135rawMonitorExit(gdata->callbackLock); \136/* Non-Bypassed CALLBACKS block here until VM_DEATH done */ \137rawMonitorEnter(gdata->callbackBlock); \138rawMonitorExit(gdata->callbackBlock); \139} \140} /* END OF CALLBACK */141142/* Forward declarations */143static void set_callbacks(jboolean on);144145/* ------------------------------------------------------------------- */146/* Global data initialization */147148/* Get initialized global data area */149static GlobalData *150get_gdata(void)151{152static GlobalData data;153154/* Create initial default values */155(void)memset(&data, 0, sizeof(GlobalData));156157data.fd = -1; /* Non-zero file or socket. */158data.heap_fd = -1; /* For heap=dump, see hprof_io */159data.check_fd = -1; /* For heap=dump, see hprof_io */160data.max_trace_depth = DEFAULT_TRACE_DEPTH;161data.prof_trace_depth = DEFAULT_TRACE_DEPTH;162data.sample_interval = DEFAULT_SAMPLE_INTERVAL;163data.lineno_in_traces = JNI_TRUE;164data.output_format = 'a'; /* 'b' for binary */165data.cutoff_point = DEFAULT_CUTOFF_POINT;166data.dump_on_exit = JNI_TRUE;167data.gc_start_time = -1L;168#ifdef DEBUG169data.debug = JNI_TRUE;170data.coredump = JNI_TRUE;171#endif172data.micro_state_accounting = JNI_FALSE;173data.force_output = JNI_TRUE;174data.verbose = JNI_TRUE;175data.primfields = JNI_TRUE;176data.primarrays = JNI_TRUE;177178data.table_serial_number_start = 1;179data.class_serial_number_start = 100000;180data.thread_serial_number_start = 200000;181data.trace_serial_number_start = 300000;182data.object_serial_number_start = 400000;183data.frame_serial_number_start = 500000;184data.gref_serial_number_start = 1;185186data.table_serial_number_counter = data.table_serial_number_start;187data.class_serial_number_counter = data.class_serial_number_start;188data.thread_serial_number_counter = data.thread_serial_number_start;189data.trace_serial_number_counter = data.trace_serial_number_start;190data.object_serial_number_counter = data.object_serial_number_start;191data.frame_serial_number_counter = data.frame_serial_number_start;192data.gref_serial_number_counter = data.gref_serial_number_start;193194data.unknown_thread_serial_num = data.thread_serial_number_counter++;195return &data;196}197198/* ------------------------------------------------------------------- */199/* Error handler callback for the java_crw_demo (classfile read write) functions. */200201static void202my_crw_fatal_error_handler(const char * msg, const char *file, int line)203{204char errmsg[256];205206(void)md_snprintf(errmsg, sizeof(errmsg),207"%s [%s:%d]", msg, file, line);208errmsg[sizeof(errmsg)-1] = 0;209HPROF_ERROR(JNI_TRUE, errmsg);210}211212static void213list_all_tables(void)214{215string_list();216class_list();217frame_list();218site_list();219object_list();220trace_list();221monitor_list();222tls_list();223loader_list();224}225226/* ------------------------------------------------------------------- */227/* Option Parsing support */228229/**230* Socket connection231*/232233/*234* Return a socket connect()ed to a "hostname" that is235* accept()ing heap profile data on "port." Return a value <= 0 if236* such a connection can't be made.237*/238static int239connect_to_socket(char *hostname, unsigned short port)240{241int fd;242243if (port == 0 || port > 65535) {244HPROF_ERROR(JNI_FALSE, "invalid port number");245return -1;246}247if (hostname == NULL) {248HPROF_ERROR(JNI_FALSE, "hostname is NULL");249return -1;250}251252/* create a socket */253fd = md_connect(hostname, port);254return fd;255}256257/* Accept a filename, and adjust the name so that it is unique for this PID */258static void259make_unique_filename(char **filename)260{261int fd;262263/* Find a file that doesn't exist */264fd = md_open(*filename);265if ( fd >= 0 ) {266int pid;267char *new_name;268char *old_name;269char *prefix;270char suffix[5];271int new_len;272273/* Close the file. */274md_close(fd);275276/* Make filename name.PID[.txt] */277pid = md_getpid();278old_name = *filename;279new_len = (int)strlen(old_name)+64;280new_name = HPROF_MALLOC(new_len);281prefix = old_name;282suffix[0] = 0;283284/* Look for .txt suffix if not binary output */285if (gdata->output_format != 'b') {286char *dot;287char *format_suffix;288289format_suffix = DEFAULT_TXT_SUFFIX;290291(void)strcpy(suffix, format_suffix);292293dot = strrchr(old_name, '.');294if ( dot != NULL ) {295int i;296int slen;297int match;298299slen = (int)strlen(format_suffix);300match = 1;301for ( i = 0; i < slen; i++ ) {302if ( dot[i]==0 ||303tolower(format_suffix[i]) != tolower(dot[i]) ) {304match = 0;305break;306}307}308if ( match ) {309(void)strcpy(suffix, dot);310*dot = 0; /* truncates prefix and old_name */311}312}313}314315/* Construct the name */316(void)md_snprintf(new_name, new_len,317"%s.%d%s", prefix, pid, suffix);318*filename = new_name;319HPROF_FREE(old_name);320321/* Odds are with Windows, this file may not be so unique. */322(void)remove(gdata->output_filename);323}324}325326static int327get_tok(char **src, char *buf, int buflen, int sep)328{329int len;330char *p;331332buf[0] = 0;333if ( **src == 0 ) {334return 0;335}336p = strchr(*src, sep);337if ( p==NULL ) {338len = (int)strlen(*src);339p = (*src) + len;340} else {341/*LINTED*/342len = (int)(p - (*src));343}344if ( (len+1) > buflen ) {345return 0;346}347(void)memcpy(buf, *src, len);348buf[len] = 0;349if ( *p != 0 && *p == sep ) {350(*src) = p+1;351} else {352(*src) = p;353}354return len;355}356357static jboolean358setBinarySwitch(char **src, jboolean *ptr)359{360char buf[80];361362if (!get_tok(src, buf, (int)sizeof(buf), ',')) {363return JNI_FALSE;364}365if (strcmp(buf, "y") == 0) {366*ptr = JNI_TRUE;367} else if (strcmp(buf, "n") == 0) {368*ptr = JNI_FALSE;369} else {370return JNI_FALSE;371}372return JNI_TRUE;373}374375static void376print_usage(void)377{378379(void)fprintf(stdout,380"\n"381" HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)\n"382"\n"383AGENTNAME " usage: java " AGENTLIB "=[help]|[<option>=<value>, ...]\n"384"\n"385"Option Name and Value Description Default\n"386"--------------------- ----------- -------\n"387"heap=dump|sites|all heap profiling all\n"388"cpu=samples|times|old CPU usage off\n"389"monitor=y|n monitor contention n\n"390"format=a|b text(txt) or binary output a\n"391"file=<file> write data to file " DEFAULT_OUTPUTFILE "[{" DEFAULT_TXT_SUFFIX "}]\n"392"net=<host>:<port> send data over a socket off\n"393"depth=<size> stack trace depth " TO_STR(DEFAULT_TRACE_DEPTH) "\n"394"interval=<ms> sample interval in ms " TO_STR(DEFAULT_SAMPLE_INTERVAL) "\n"395"cutoff=<value> output cutoff point " TO_STR(DEFAULT_CUTOFF_POINT) "\n"396"lineno=y|n line number in traces? y\n"397"thread=y|n thread in traces? n\n"398"doe=y|n dump on exit? y\n"399"msa=y|n Solaris micro state accounting n\n"400"force=y|n force output to <file> y\n"401"verbose=y|n print messages about dumps y\n"402"\n"403"Obsolete Options\n"404"----------------\n"405"gc_okay=y|n\n"406407#ifdef DEBUG408"\n"409"DEBUG Option Description Default\n"410"------------ ----------- -------\n"411"primfields=y|n include primitive field values y\n"412"primarrays=y|n include primitive array values y\n"413"debugflags=MASK Various debug flags 0\n"414" 0x01 Report refs in and of unprepared classes\n"415"logflags=MASK Logging to stderr 0\n"416" " TO_STR(LOG_DUMP_MISC) " Misc logging\n"417" " TO_STR(LOG_DUMP_LISTS) " Dump out the tables\n"418" " TO_STR(LOG_CHECK_BINARY) " Verify & dump format=b\n"419"coredump=y|n Core dump on fatal n\n"420"errorexit=y|n Exit on any error n\n"421"pause=y|n Pause on onload & echo PID n\n"422"debug=y|n Turn on all debug checking n\n"423"X=MASK Internal use only 0\n"424425"\n"426"Environment Variables\n"427"---------------------\n"428"_JAVA_HPROF_OPTIONS\n"429" Options can be added externally via this environment variable.\n"430" Anything contained in it will get a comma prepended to it (if needed),\n"431" then it will be added to the end of the options supplied via the\n"432" " XRUN " or " AGENTLIB " command line option.\n"433434#endif435436"\n"437"Examples\n"438"--------\n"439" - Get sample cpu information every 20 millisec, with a stack depth of 3:\n"440" java " AGENTLIB "=cpu=samples,interval=20,depth=3 classname\n"441" - Get heap usage information based on the allocation sites:\n"442" java " AGENTLIB "=heap=sites classname\n"443444#ifdef DEBUG445" - Using the external option addition with csh, log details on all runs:\n"446" setenv _JAVA_HPROF_OPTIONS \"logflags=0xC\"\n"447" java " AGENTLIB "=cpu=samples classname\n"448" is the same as:\n"449" java " AGENTLIB "=cpu=samples,logflags=0xC classname\n"450#endif451452"\n"453"Notes\n"454"-----\n"455" - The option format=b cannot be used with monitor=y.\n"456" - The option format=b cannot be used with cpu=old|times.\n"457" - Use of the " XRUN " interface can still be used, e.g.\n"458" java " XRUN ":[help]|[<option>=<value>, ...]\n"459" will behave exactly the same as:\n"460" java " AGENTLIB "=[help]|[<option>=<value>, ...]\n"461462#ifdef DEBUG463" - The debug options and environment variables are available with both java\n"464" and java_g versions.\n"465#endif466467"\n"468"Warnings\n"469"--------\n"470" - This is demonstration code for the JVMTI interface and use of BCI,\n"471" it is not an official product or formal part of the JDK.\n"472" - The " XRUN " interface will be removed in a future release.\n"473" - The option format=b is considered experimental, this format may change\n"474" in a future release.\n"475476#ifdef DEBUG477" - The obsolete options may be completely removed in a future release.\n"478" - The debug options and environment variables are not considered public\n"479" interfaces and can change or be removed with any type of update of\n"480" " AGENTNAME ", including patches.\n"481#endif482483);484}485486static void487option_error(char *description)488{489char errmsg[FILENAME_MAX+80];490491(void)md_snprintf(errmsg, sizeof(errmsg),492"%s option error: %s (%s)", AGENTNAME, description, gdata->options);493errmsg[sizeof(errmsg)-1] = 0;494HPROF_ERROR(JNI_FALSE, errmsg);495error_exit_process(1);496}497498static void499parse_options(char *command_line_options)500{501int file_or_net_option_seen = JNI_FALSE;502char *all_options;503char *extra_options;504char *options;505char *default_filename;506int ulen;507508if (command_line_options == 0)509command_line_options = "";510511if ((strcmp(command_line_options, "help")) == 0) {512print_usage();513error_exit_process(0);514}515516extra_options = getenv("_JAVA_HPROF_OPTIONS");517if ( extra_options == NULL ) {518extra_options = "";519}520521all_options = HPROF_MALLOC((int)strlen(command_line_options) +522(int)strlen(extra_options) + 2);523gdata->options = all_options;524(void)strcpy(all_options, command_line_options);525if ( extra_options[0] != 0 ) {526if ( all_options[0] != 0 ) {527(void)strcat(all_options, ",");528}529(void)strcat(all_options, extra_options);530}531options = all_options;532533LOG2("parse_options()", all_options);534535while (*options) {536char option[16];537char suboption[FILENAME_MAX+1];538char *endptr;539540if (!get_tok(&options, option, (int)sizeof(option), '=')) {541option_error("general syntax error parsing options");542}543if (strcmp(option, "file") == 0) {544if ( file_or_net_option_seen ) {545option_error("file or net options should only appear once");546}547if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {548option_error("syntax error parsing file=filename");549}550gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(suboption)+1);551(void)strcpy(gdata->utf8_output_filename, suboption);552file_or_net_option_seen = JNI_TRUE;553} else if (strcmp(option, "net") == 0) {554char port_number[16];555if (file_or_net_option_seen ) {556option_error("file or net options should only appear once");557}558if (!get_tok(&options, suboption, (int)sizeof(suboption), ':')) {559option_error("net option missing ':'");560}561if (!get_tok(&options, port_number, (int)sizeof(port_number), ',')) {562option_error("net option missing port");563}564gdata->net_hostname = HPROF_MALLOC((int)strlen(suboption)+1);565(void)strcpy(gdata->net_hostname, suboption);566gdata->net_port = (int)strtol(port_number, NULL, 10);567file_or_net_option_seen = JNI_TRUE;568} else if (strcmp(option, "format") == 0) {569if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {570option_error("syntax error parsing format=a|b");571}572if (strcmp(suboption, "a") == 0) {573gdata->output_format = 'a';574} else if (strcmp(suboption, "b") == 0) {575gdata->output_format = 'b';576} else {577option_error("format option value must be a|b");578}579} else if (strcmp(option, "depth") == 0) {580if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {581option_error("syntax error parsing depth=DECIMAL");582}583gdata->max_trace_depth = (int)strtol(suboption, &endptr, 10);584if ((endptr != NULL && *endptr != 0) || gdata->max_trace_depth < 0) {585option_error("depth option value must be decimal and >= 0");586}587gdata->prof_trace_depth = gdata->max_trace_depth;588} else if (strcmp(option, "interval") == 0) {589if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {590option_error("syntax error parsing interval=DECIMAL");591}592gdata->sample_interval = (int)strtol(suboption, &endptr, 10);593if ((endptr != NULL && *endptr != 0) || gdata->sample_interval <= 0) {594option_error("interval option value must be decimal and > 0");595}596} else if (strcmp(option, "cutoff") == 0) {597if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {598option_error("syntax error parsing cutoff=DOUBLE");599}600gdata->cutoff_point = strtod(suboption, &endptr);601if ((endptr != NULL && *endptr != 0) || gdata->cutoff_point < 0) {602option_error("cutoff option value must be floating point and >= 0");603}604} else if (strcmp(option, "cpu") == 0) {605if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {606option_error("syntax error parsing cpu=y|samples|times|old");607}608if ((strcmp(suboption, "samples") == 0) ||609(strcmp(suboption, "y") == 0)) {610gdata->cpu_sampling = JNI_TRUE;611} else if (strcmp(suboption, "times") == 0) {612gdata->cpu_timing = JNI_TRUE;613gdata->old_timing_format = JNI_FALSE;614} else if (strcmp(suboption, "old") == 0) {615gdata->cpu_timing = JNI_TRUE;616gdata->old_timing_format = JNI_TRUE;617} else {618option_error("cpu option value must be y|samples|times|old");619}620} else if (strcmp(option, "heap") == 0) {621if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {622option_error("syntax error parsing heap=dump|sites|all");623}624if (strcmp(suboption, "dump") == 0) {625gdata->heap_dump = JNI_TRUE;626} else if (strcmp(suboption, "sites") == 0) {627gdata->alloc_sites = JNI_TRUE;628} else if (strcmp(suboption, "all") == 0) {629gdata->heap_dump = JNI_TRUE;630gdata->alloc_sites = JNI_TRUE;631} else {632option_error("heap option value must be dump|sites|all");633}634} else if( strcmp(option,"lineno") == 0) {635if ( !setBinarySwitch(&options, &(gdata->lineno_in_traces)) ) {636option_error("lineno option value must be y|n");637}638} else if( strcmp(option,"thread") == 0) {639if ( !setBinarySwitch(&options, &(gdata->thread_in_traces)) ) {640option_error("thread option value must be y|n");641}642} else if( strcmp(option,"doe") == 0) {643if ( !setBinarySwitch(&options, &(gdata->dump_on_exit)) ) {644option_error("doe option value must be y|n");645}646} else if( strcmp(option,"msa") == 0) {647if ( !setBinarySwitch(&options, &(gdata->micro_state_accounting)) ) {648option_error("msa option value must be y|n");649}650} else if( strcmp(option,"force") == 0) {651if ( !setBinarySwitch(&options, &(gdata->force_output)) ) {652option_error("force option value must be y|n");653}654} else if( strcmp(option,"verbose") == 0) {655if ( !setBinarySwitch(&options, &(gdata->verbose)) ) {656option_error("verbose option value must be y|n");657}658} else if( strcmp(option,"primfields") == 0) {659if ( !setBinarySwitch(&options, &(gdata->primfields)) ) {660option_error("primfields option value must be y|n");661}662} else if( strcmp(option,"primarrays") == 0) {663if ( !setBinarySwitch(&options, &(gdata->primarrays)) ) {664option_error("primarrays option value must be y|n");665}666} else if( strcmp(option,"monitor") == 0) {667if ( !setBinarySwitch(&options, &(gdata->monitor_tracing)) ) {668option_error("monitor option value must be y|n");669}670} else if( strcmp(option,"gc_okay") == 0) {671if ( !setBinarySwitch(&options, &(gdata->gc_okay)) ) {672option_error("gc_okay option value must be y|n");673}674} else if (strcmp(option, "logflags") == 0) {675if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {676option_error("logflags option value must be numeric");677}678gdata->logflags = (int)strtol(suboption, NULL, 0);679} else if (strcmp(option, "debugflags") == 0) {680if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {681option_error("debugflags option value must be numeric");682}683gdata->debugflags = (int)strtol(suboption, NULL, 0);684} else if (strcmp(option, "coredump") == 0) {685if ( !setBinarySwitch(&options, &(gdata->coredump)) ) {686option_error("coredump option value must be y|n");687}688} else if (strcmp(option, "exitpause") == 0) {689option_error("The exitpause option was removed, use -XX:OnError='cmd %%p'");690} else if (strcmp(option, "errorexit") == 0) {691if ( !setBinarySwitch(&options, &(gdata->errorexit)) ) {692option_error("errorexit option value must be y|n");693}694} else if (strcmp(option, "pause") == 0) {695if ( !setBinarySwitch(&options, &(gdata->pause)) ) {696option_error("pause option value must be y|n");697}698} else if (strcmp(option, "debug") == 0) {699if ( !setBinarySwitch(&options, &(gdata->debug)) ) {700option_error("debug option value must be y|n");701}702} else if (strcmp(option, "precrash") == 0) {703option_error("The precrash option was removed, use -XX:OnError='precrash -p %%p'");704} else if (strcmp(option, "X") == 0) {705if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {706option_error("X option value must be numeric");707}708gdata->experiment = (int)strtol(suboption, NULL, 0);709} else {710char errmsg[80];711(void)strcpy(errmsg, "Unknown option: ");712(void)strcat(errmsg, option);713option_error(errmsg);714}715}716717if (gdata->output_format == 'b') {718if (gdata->cpu_timing) {719option_error("cpu=times|old is not supported with format=b");720}721if (gdata->monitor_tracing) {722option_error("monitor=y is not supported with format=b");723}724}725726if (gdata->old_timing_format) {727gdata->prof_trace_depth = 2;728}729730if (gdata->output_format == 'b') {731default_filename = DEFAULT_OUTPUTFILE;732} else {733default_filename = DEFAULT_OUTPUTFILE DEFAULT_TXT_SUFFIX;734}735736if (!file_or_net_option_seen) {737gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(default_filename)+1);738(void)strcpy(gdata->utf8_output_filename, default_filename);739}740741if ( gdata->utf8_output_filename != NULL ) {742/* UTF-8 to platform encoding (fill in gdata->output_filename) */743ulen = (int)strlen(gdata->utf8_output_filename);744gdata->output_filename = (char*)HPROF_MALLOC(ulen*3+3);745#ifdef SKIP_NPT746(void)strcpy(gdata->output_filename, gdata->utf8_output_filename);747#else748(void)(gdata->npt->utf8ToPlatform)749(gdata->npt->utf, (jbyte*)gdata->utf8_output_filename, ulen,750gdata->output_filename, ulen*3+3);751#endif752}753754/* By default we turn on gdata->alloc_sites and gdata->heap_dump */755if ( !gdata->cpu_timing &&756!gdata->cpu_sampling &&757!gdata->monitor_tracing &&758!gdata->alloc_sites &&759!gdata->heap_dump) {760gdata->heap_dump = JNI_TRUE;761gdata->alloc_sites = JNI_TRUE;762}763764if ( gdata->alloc_sites || gdata->heap_dump ) {765gdata->obj_watch = JNI_TRUE;766}767if ( gdata->obj_watch || gdata->cpu_timing ) {768gdata->bci = JNI_TRUE;769}770771/* Create files & sockets needed */772if (gdata->heap_dump) {773char *base;774int len;775776/* Get a fast tempfile for the heap information */777base = gdata->output_filename;778if ( base==NULL ) {779base = default_filename;780}781len = (int)strlen(base);782gdata->heapfilename = HPROF_MALLOC(len + 5);783(void)strcpy(gdata->heapfilename, base);784(void)strcat(gdata->heapfilename, ".TMP");785make_unique_filename(&(gdata->heapfilename));786(void)remove(gdata->heapfilename);787if (gdata->output_format == 'b') {788if ( gdata->logflags & LOG_CHECK_BINARY ) {789char * check_suffix;790791check_suffix = ".check" DEFAULT_TXT_SUFFIX;792gdata->checkfilename =793HPROF_MALLOC((int)strlen(default_filename)+794(int)strlen(check_suffix)+1);795(void)strcpy(gdata->checkfilename, default_filename);796(void)strcat(gdata->checkfilename, check_suffix);797(void)remove(gdata->checkfilename);798gdata->check_fd = md_creat(gdata->checkfilename);799}800if ( gdata->debug ) {801gdata->logflags |= LOG_CHECK_BINARY;802}803gdata->heap_fd = md_creat_binary(gdata->heapfilename);804} else {805gdata->heap_fd = md_creat(gdata->heapfilename);806}807if ( gdata->heap_fd < 0 ) {808char errmsg[FILENAME_MAX+80];809810(void)md_snprintf(errmsg, sizeof(errmsg),811"can't create temp heap file: %s", gdata->heapfilename);812errmsg[sizeof(errmsg)-1] = 0;813HPROF_ERROR(JNI_TRUE, errmsg);814}815}816817if ( gdata->net_port > 0 ) {818LOG2("Agent_OnLoad", "Connecting to socket");819gdata->fd = connect_to_socket(gdata->net_hostname, (unsigned short)gdata->net_port);820if (gdata->fd <= 0) {821char errmsg[120];822823(void)md_snprintf(errmsg, sizeof(errmsg),824"can't connect to %s:%u", gdata->net_hostname, gdata->net_port);825errmsg[sizeof(errmsg)-1] = 0;826HPROF_ERROR(JNI_FALSE, errmsg);827error_exit_process(1);828}829gdata->socket = JNI_TRUE;830} else {831/* If going out to a file, obey the force=y|n option */832if ( !gdata->force_output ) {833make_unique_filename(&(gdata->output_filename));834}835/* Make doubly sure this file does NOT exist */836(void)remove(gdata->output_filename);837/* Create the file */838if (gdata->output_format == 'b') {839gdata->fd = md_creat_binary(gdata->output_filename);840} else {841gdata->fd = md_creat(gdata->output_filename);842}843if (gdata->fd < 0) {844char errmsg[FILENAME_MAX+80];845846(void)md_snprintf(errmsg, sizeof(errmsg),847"can't create profile file: %s", gdata->output_filename);848errmsg[sizeof(errmsg)-1] = 0;849HPROF_ERROR(JNI_FALSE, errmsg);850error_exit_process(1);851}852}853854}855856/* ------------------------------------------------------------------- */857/* Data reset and dump functions */858859static void860reset_all_data(void)861{862if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) {863rawMonitorEnter(gdata->data_access_lock);864}865866if (gdata->cpu_sampling || gdata->cpu_timing) {867trace_clear_cost();868}869if (gdata->monitor_tracing) {870monitor_clear();871}872873if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) {874rawMonitorExit(gdata->data_access_lock);875}876}877878static void reset_class_load_status(JNIEnv *env, jthread thread);879880static void881dump_all_data(JNIEnv *env)882{883verbose_message("Dumping");884if (gdata->monitor_tracing) {885verbose_message(" contended monitor usage ...");886tls_dump_monitor_state(env);887monitor_write_contended_time(env, gdata->cutoff_point);888}889if (gdata->heap_dump) {890verbose_message(" Java heap ...");891/* Update the class table */892reset_class_load_status(env, NULL);893site_heapdump(env);894}895if (gdata->alloc_sites) {896verbose_message(" allocation sites ...");897site_write(env, 0, gdata->cutoff_point);898}899if (gdata->cpu_sampling) {900verbose_message(" CPU usage by sampling running threads ...");901trace_output_cost(env, gdata->cutoff_point);902}903if (gdata->cpu_timing) {904if (!gdata->old_timing_format) {905verbose_message(" CPU usage by timing methods ...");906trace_output_cost(env, gdata->cutoff_point);907} else {908verbose_message(" CPU usage in old prof format ...");909trace_output_cost_in_prof_format(env);910}911}912reset_all_data();913io_flush();914verbose_message(" done.\n");915}916917/* ------------------------------------------------------------------- */918/* Dealing with class load and unload status */919920static void921reset_class_load_status(JNIEnv *env, jthread thread)922{923924WITH_LOCAL_REFS(env, 1) {925jint class_count;926jclass *classes;927jint i;928929/* Get all classes from JVMTI, make sure they are in the class table. */930getLoadedClasses(&classes, &class_count);931932/* We don't know if the class list has changed really, so we933* guess by the class count changing. Don't want to do934* a bunch of work on classes when it's unnecessary.935* I assume that even though we have global references on the936* jclass object that the class is still considered unloaded.937* (e.g. GC of jclass isn't required for it to be included938* in the unloaded list, or not in the load list)939* [Note: Use of Weak references was a performance problem.]940*/941if ( class_count != gdata->class_count ) {942943rawMonitorEnter(gdata->data_access_lock); {944945/* Unmark the classes in the load list */946class_all_status_remove(CLASS_IN_LOAD_LIST);947948/* Pretend like it was a class load event */949for ( i = 0 ; i < class_count ; i++ ) {950jobject loader;951952loader = getClassLoader(classes[i]);953event_class_load(env, thread, classes[i], loader);954}955956/* Process the classes that have been unloaded */957class_do_unloads(env);958959} rawMonitorExit(gdata->data_access_lock);960961}962963/* Free the space and save the count. */964jvmtiDeallocate(classes);965gdata->class_count = class_count;966967} END_WITH_LOCAL_REFS;968969}970971/* A GC or Death event has happened, so do some cleanup */972static void973object_free_cleanup(JNIEnv *env, jboolean force_class_table_reset)974{975Stack *stack;976977/* Then we process the ObjectFreeStack */978rawMonitorEnter(gdata->object_free_lock); {979stack = gdata->object_free_stack;980gdata->object_free_stack = NULL; /* Will trigger new stack */981} rawMonitorExit(gdata->object_free_lock);982983/* Notice we just grabbed the stack of freed objects so984* any object free events will create a new stack.985*/986if ( stack != NULL ) {987int count;988int i;989990count = stack_depth(stack);991992/* If we saw something freed in this GC */993if ( count > 0 ) {994995for ( i = 0 ; i < count ; i++ ) {996ObjectIndex object_index;997jlong tag;998999tag = *(jlong*)stack_element(stack,i);1000object_index = tag_extract(tag);10011002(void)object_free(object_index);1003}10041005/* We reset the class load status (only do this once) */1006reset_class_load_status(env, NULL);1007force_class_table_reset = JNI_FALSE;10081009}10101011/* Just terminate this stack object */1012stack_term(stack);1013}10141015/* We reset the class load status if we haven't and need to */1016if ( force_class_table_reset ) {1017reset_class_load_status(env, NULL);1018}10191020}10211022/* Main function for thread that watches for GC finish events */1023static void JNICALL1024gc_finish_watcher(jvmtiEnv *jvmti, JNIEnv *env, void *p)1025{1026jboolean active;10271028active = JNI_TRUE;10291030/* Indicate the watcher thread is active */1031rawMonitorEnter(gdata->gc_finish_lock); {1032gdata->gc_finish_active = JNI_TRUE;1033} rawMonitorExit(gdata->gc_finish_lock);10341035/* Loop while active */1036while ( active ) {1037jboolean do_cleanup;10381039do_cleanup = JNI_FALSE;1040rawMonitorEnter(gdata->gc_finish_lock); {1041/* Don't wait if VM_DEATH wants us to quit */1042if ( gdata->gc_finish_stop_request ) {1043/* Time to terminate */1044active = JNI_FALSE;1045} else {1046/* Wait for notification to do cleanup, or terminate */1047rawMonitorWait(gdata->gc_finish_lock, 0);1048/* After wait, check to see if VM_DEATH wants us to quit */1049if ( gdata->gc_finish_stop_request ) {1050/* Time to terminate */1051active = JNI_FALSE;1052}1053}1054if ( active && gdata->gc_finish > 0 ) {1055/* Time to cleanup, reset count and prepare for cleanup */1056gdata->gc_finish = 0;1057do_cleanup = JNI_TRUE;1058}1059} rawMonitorExit(gdata->gc_finish_lock);10601061/* Do the cleanup if requested outside gc_finish_lock */1062if ( do_cleanup ) {1063/* Free up all freed objects, don't force class table reset1064* We cannot let the VM_DEATH complete while we are doing1065* this cleanup. So if during this, VM_DEATH happens,1066* the VM_DEATH callback should block waiting for this1067* loop to terminate, and send a notification to the1068* VM_DEATH thread.1069*/1070object_free_cleanup(env, JNI_FALSE);10711072/* Cleanup the tls table where the Thread objects were GC'd */1073tls_garbage_collect(env);1074}10751076}10771078/* Falling out means VM_DEATH is happening, we need to notify VM_DEATH1079* that we are done doing the cleanup. VM_DEATH is waiting on this1080* notify.1081*/1082rawMonitorEnter(gdata->gc_finish_lock); {1083gdata->gc_finish_active = JNI_FALSE;1084rawMonitorNotifyAll(gdata->gc_finish_lock);1085} rawMonitorExit(gdata->gc_finish_lock);1086}10871088/* ------------------------------------------------------------------- */1089/* JVMTI Event callback functions */10901091static void1092setup_event_mode(jboolean onload_set_only, jvmtiEventMode state)1093{1094if ( onload_set_only ) {1095setEventNotificationMode(state,1096JVMTI_EVENT_VM_INIT, NULL);1097setEventNotificationMode(state,1098JVMTI_EVENT_VM_DEATH, NULL);1099if (gdata->bci) {1100setEventNotificationMode(state,1101JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);1102}1103} else {1104/* Enable all other JVMTI events of interest now. */1105setEventNotificationMode(state,1106JVMTI_EVENT_THREAD_START, NULL);1107setEventNotificationMode(state,1108JVMTI_EVENT_THREAD_END, NULL);1109setEventNotificationMode(state,1110JVMTI_EVENT_CLASS_LOAD, NULL);1111setEventNotificationMode(state,1112JVMTI_EVENT_CLASS_PREPARE, NULL);1113setEventNotificationMode(state,1114JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);1115if (gdata->cpu_timing) {1116setEventNotificationMode(state,1117JVMTI_EVENT_EXCEPTION_CATCH, NULL);1118}1119if (gdata->monitor_tracing) {1120setEventNotificationMode(state,1121JVMTI_EVENT_MONITOR_WAIT, NULL);1122setEventNotificationMode(state,1123JVMTI_EVENT_MONITOR_WAITED, NULL);1124setEventNotificationMode(state,1125JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);1126setEventNotificationMode(state,1127JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);1128}1129if (gdata->obj_watch) {1130setEventNotificationMode(state,1131JVMTI_EVENT_OBJECT_FREE, NULL);1132}1133setEventNotificationMode(state,1134JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);1135setEventNotificationMode(state,1136JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);1137}1138}11391140/* JVMTI_EVENT_VM_INIT */1141static void JNICALL1142cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)1143{1144rawMonitorEnter(gdata->data_access_lock); {11451146LoaderIndex loader_index;1147ClassIndex cnum;1148TlsIndex tls_index;11491150gdata->jvm_initializing = JNI_TRUE;11511152/* Header to use in heap dumps */1153gdata->header = "JAVA PROFILE 1.0.1";1154gdata->segmented = JNI_FALSE;1155if (gdata->output_format == 'b') {1156/* We need JNI here to call in and get the current maximum memory */1157gdata->maxMemory = getMaxMemory(env);1158gdata->maxHeapSegment = (jlong)2000000000;1159/* More than 2Gig triggers segments and 1.0.2 */1160if ( gdata->maxMemory >= gdata->maxHeapSegment ) {1161gdata->header = "JAVA PROFILE 1.0.2";1162gdata->segmented = JNI_TRUE; /* 1.0.2 */1163}1164}11651166/* We write the initial header after the VM initializes now1167* because we needed to use JNI to get maxMemory and determine if1168* a 1.0.1 or a 1.0.2 header will be used.1169* This used to be done in Agent_OnLoad.1170*/1171io_write_file_header();11721173LOG("cbVMInit begin");11741175/* Create a system loader entry first */1176loader_index = loader_find_or_create(NULL,NULL);11771178/* Find the thread jclass (does JNI calls) */1179gdata->thread_cnum = class_find_or_create("Ljava/lang/Thread;",1180loader_index);1181class_add_status(gdata->thread_cnum, CLASS_SYSTEM);11821183/* Issue fake system thread start */1184tls_index = tls_find_or_create(env, thread);11851186/* Setup the Tracker class (should be first class in table) */1187tracker_setup_class();11881189/* Find selected system classes to keep track of */1190gdata->system_class_size = 0;1191cnum = class_find_or_create("Ljava/lang/Object;", loader_index);11921193gdata->system_trace_index = tls_get_trace(tls_index, env,1194gdata->max_trace_depth, JNI_FALSE);1195gdata->system_object_site_index = site_find_or_create(1196cnum, gdata->system_trace_index);11971198/* Used to ID HPROF generated items */1199gdata->hprof_trace_index = tls_get_trace(tls_index, env,1200gdata->max_trace_depth, JNI_FALSE);1201gdata->hprof_site_index = site_find_or_create(1202cnum, gdata->hprof_trace_index);12031204if ( gdata->logflags & LOG_DUMP_LISTS ) {1205list_all_tables();1206}12071208/* Prime the class table */1209reset_class_load_status(env, thread);12101211/* Find the tracker jclass and jmethodID's (does JNI calls) */1212if ( gdata->bci ) {1213tracker_setup_methods(env);1214}12151216/* Start any agent threads (does JNI, JVMTI, and Java calls) */12171218/* Thread to watch for gc_finish events */1219rawMonitorEnter(gdata->gc_finish_lock); {1220createAgentThread(env, "HPROF gc_finish watcher",1221&gc_finish_watcher);1222} rawMonitorExit(gdata->gc_finish_lock);12231224/* Start up listener thread if we need it */1225if ( gdata->socket ) {1226listener_init(env);1227}12281229/* Start up cpu sampling thread if we need it */1230if ( gdata->cpu_sampling ) {1231/* Note: this could also get started later (see cpu) */1232cpu_sample_init(env);1233}12341235/* Setup event modes */1236setup_event_mode(JNI_FALSE, JVMTI_ENABLE);12371238/* Engage tracking (sets Java Tracker field so injections call into1239* agent library).1240*/1241if ( gdata->bci ) {1242tracker_engage(env);1243}12441245/* Indicate the VM is initialized now */1246gdata->jvm_initialized = JNI_TRUE;1247gdata->jvm_initializing = JNI_FALSE;12481249LOG("cbVMInit end");12501251} rawMonitorExit(gdata->data_access_lock);1252}12531254/* JVMTI_EVENT_VM_DEATH */1255static void JNICALL1256cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env)1257{1258/*1259* Use local flag to minimize gdata->dump_lock hold time.1260*/1261jboolean need_to_dump = JNI_FALSE;12621263LOG("cbVMDeath");12641265/* Shutdown thread watching gc_finish, outside CALLBACK locks.1266* We need to make sure the watcher thread is done doing any cleanup1267* work before we continue here.1268*/1269rawMonitorEnter(gdata->gc_finish_lock); {1270/* Notify watcher thread to finish up, it will send1271* another notify when done. If the watcher thread is busy1272* cleaning up, it will detect gc_finish_stop_request when it's done.1273* Then it sets gc_finish_active to JNI_FALSE and will notify us.1274* If the watcher thread is waiting to be notified, then the1275* notification wakes it up.1276* We do not want to do the VM_DEATH while the gc_finish1277* watcher thread is in the middle of a cleanup.1278*/1279gdata->gc_finish_stop_request = JNI_TRUE;1280rawMonitorNotifyAll(gdata->gc_finish_lock);1281/* Wait for the gc_finish watcher thread to notify us it's done */1282while ( gdata->gc_finish_active ) {1283rawMonitorWait(gdata->gc_finish_lock,0);1284}1285} rawMonitorExit(gdata->gc_finish_lock);12861287/* The gc_finish watcher thread should be done now, or done shortly. */128812891290/* BEGIN_CALLBACK/END_CALLBACK handling. */12911292/* The callbackBlock prevents any active callbacks from returning1293* back to the VM, and also blocks all new callbacks.1294* We want to prevent any threads from premature death, so1295* that we don't have worry about that during thread queries1296* in this final dump process.1297*/1298rawMonitorEnter(gdata->callbackBlock); {12991300/* We need to wait for all callbacks actively executing to block1301* on exit, and new ones will block on entry.1302* The BEGIN_CALLBACK/END_CALLBACK macros keep track of callbacks1303* that are active.1304* Once the last active callback is done, it will notify this1305* thread and block.1306*/13071308rawMonitorEnter(gdata->callbackLock); {1309/* Turn off native calls */1310if ( gdata->bci ) {1311tracker_disengage(env);1312}1313gdata->vm_death_callback_active = JNI_TRUE;1314while (gdata->active_callbacks > 0) {1315rawMonitorWait(gdata->callbackLock, 0);1316}1317} rawMonitorExit(gdata->callbackLock);13181319/* Now we know that no threads will die on us, being blocked1320* on some event callback, at a minimum ThreadEnd.1321*/13221323/* Make some basic checks. */1324rawMonitorEnter(gdata->data_access_lock); {1325if ( gdata->jvm_initializing ) {1326HPROF_ERROR(JNI_TRUE, "VM Death during VM Init");1327return;1328}1329if ( !gdata->jvm_initialized ) {1330HPROF_ERROR(JNI_TRUE, "VM Death before VM Init");1331return;1332}1333if (gdata->jvm_shut_down) {1334HPROF_ERROR(JNI_TRUE, "VM Death more than once?");1335return;1336}1337} rawMonitorExit(gdata->data_access_lock);13381339/* Shutdown the cpu loop thread */1340if ( gdata->cpu_sampling ) {1341cpu_sample_term(env);1342}13431344/* Time to dump the final data */1345rawMonitorEnter(gdata->dump_lock); {13461347gdata->jvm_shut_down = JNI_TRUE;13481349if (!gdata->dump_in_process) {1350need_to_dump = JNI_TRUE;1351gdata->dump_in_process = JNI_TRUE;1352/*1353* Setting gdata->dump_in_process will cause cpu sampling to pause1354* (if we are sampling). We don't resume sampling after the1355* dump_all_data() call below because the VM is shutting1356* down.1357*/1358}13591360} rawMonitorExit(gdata->dump_lock);13611362/* Dump everything if we need to */1363if (gdata->dump_on_exit && need_to_dump) {13641365dump_all_data(env);1366}13671368/* Disable all events and callbacks now, all of them.1369* NOTE: It's important that this be done after the dump1370* it prevents other threads from messing up the data1371* because they will block on ThreadStart and ThreadEnd1372* events due to the CALLBACK block.1373*/1374set_callbacks(JNI_FALSE);1375setup_event_mode(JNI_FALSE, JVMTI_DISABLE);1376setup_event_mode(JNI_TRUE, JVMTI_DISABLE);13771378/* Write tail of file */1379io_write_file_footer();13801381} rawMonitorExit(gdata->callbackBlock);13821383/* Shutdown the listener thread and socket, or flush I/O buffers */1384if (gdata->socket) {1385listener_term(env);1386} else {1387io_flush();1388}13891390/* Close the file descriptors down */1391if ( gdata->fd >= 0 ) {1392(void)md_close(gdata->fd);1393gdata->fd = -1;1394if ( gdata->logflags & LOG_CHECK_BINARY ) {1395if (gdata->output_format == 'b' && gdata->output_filename != NULL) {1396check_binary_file(gdata->output_filename);1397}1398}1399}1400if ( gdata->heap_fd >= 0 ) {1401(void)md_close(gdata->heap_fd);1402gdata->heap_fd = -1;1403}14041405if ( gdata->check_fd >= 0 ) {1406(void)md_close(gdata->check_fd);1407gdata->check_fd = -1;1408}14091410/* Remove the temporary heap file */1411if (gdata->heap_dump) {1412(void)remove(gdata->heapfilename);1413}14141415/* If logging, dump the tables */1416if ( gdata->logflags & LOG_DUMP_LISTS ) {1417list_all_tables();1418}14191420/* Make sure all global references are deleted */1421class_delete_global_references(env);1422loader_delete_global_references(env);1423tls_delete_global_references(env);14241425}14261427/* JVMTI_EVENT_THREAD_START */1428static void JNICALL1429cbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)1430{1431LOG3("cbThreadStart", "thread is", (int)(long)(ptrdiff_t)thread);14321433BEGIN_CALLBACK() {1434event_thread_start(env, thread);1435} END_CALLBACK();1436}14371438/* JVMTI_EVENT_THREAD_END */1439static void JNICALL1440cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)1441{1442LOG3("cbThreadEnd", "thread is", (int)(long)(ptrdiff_t)thread);14431444BEGIN_CALLBACK() {1445event_thread_end(env, thread);1446} END_CALLBACK();1447}14481449/* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */1450static void JNICALL1451cbClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv* env,1452jclass class_being_redefined, jobject loader,1453const char* name, jobject protection_domain,1454jint class_data_len, const unsigned char* class_data,1455jint* new_class_data_len, unsigned char** new_class_data)1456{14571458/* WARNING: This will be called before VM_INIT. */14591460LOG2("cbClassFileLoadHook:",(name==NULL?"Unknown":name));14611462if (!gdata->bci) {1463return;1464}14651466BEGIN_CALLBACK() {1467rawMonitorEnter(gdata->data_access_lock); {1468const char *classname;14691470if ( gdata->bci_counter == 0 ) {1471/* Prime the system classes */1472class_prime_system_classes();1473}14741475gdata->bci_counter++;14761477*new_class_data_len = 0;1478*new_class_data = NULL;14791480/* Name could be NULL */1481if ( name == NULL ) {1482classname = ((JavaCrwDemoClassname)1483(gdata->java_crw_demo_classname_function))1484(class_data, class_data_len, &my_crw_fatal_error_handler);1485if ( classname == NULL ) {1486HPROF_ERROR(JNI_TRUE, "No classname in classfile");1487}1488} else {1489classname = strdup(name);1490if ( classname == NULL ) {1491HPROF_ERROR(JNI_TRUE, "Ran out of malloc() space");1492}1493}14941495/* The tracker class itself? */1496if ( strcmp(classname, TRACKER_CLASS_NAME) != 0 ) {1497ClassIndex cnum;1498int system_class;1499unsigned char * new_image;1500long new_length;1501int len;1502char *signature;1503LoaderIndex loader_index;15041505LOG2("cbClassFileLoadHook injecting class" , classname);15061507/* Define a unique class number for this class */1508len = (int)strlen(classname);1509signature = HPROF_MALLOC(len+3);1510signature[0] = JVM_SIGNATURE_CLASS;1511(void)memcpy(signature+1, classname, len);1512signature[len+1] = JVM_SIGNATURE_ENDCLASS;1513signature[len+2] = 0;1514loader_index = loader_find_or_create(env,loader);1515if ( class_being_redefined != NULL ) {1516cnum = class_find_or_create(signature, loader_index);1517} else {1518cnum = class_create(signature, loader_index);1519}1520HPROF_FREE(signature);1521signature = NULL;15221523/* Make sure class doesn't get unloaded by accident */1524class_add_status(cnum, CLASS_IN_LOAD_LIST);15251526/* Is it a system class? */1527system_class = 0;1528if ( (!gdata->jvm_initialized)1529&& (!gdata->jvm_initializing)1530&& ( ( class_get_status(cnum) & CLASS_SYSTEM) != 01531|| gdata->bci_counter < 8 ) ) {1532system_class = 1;1533LOG2(classname, " is a system class");1534}15351536new_image = NULL;1537new_length = 0;15381539/* Call the class file reader/write demo code */1540((JavaCrwDemo)(gdata->java_crw_demo_function))(1541cnum,1542classname,1543class_data,1544class_data_len,1545system_class,1546TRACKER_CLASS_NAME,1547TRACKER_CLASS_SIG,1548(gdata->cpu_timing)?TRACKER_CALL_NAME:NULL,1549(gdata->cpu_timing)?TRACKER_CALL_SIG:NULL,1550(gdata->cpu_timing)?TRACKER_RETURN_NAME:NULL,1551(gdata->cpu_timing)?TRACKER_RETURN_SIG:NULL,1552(gdata->obj_watch)?TRACKER_OBJECT_INIT_NAME:NULL,1553(gdata->obj_watch)?TRACKER_OBJECT_INIT_SIG:NULL,1554(gdata->obj_watch)?TRACKER_NEWARRAY_NAME:NULL,1555(gdata->obj_watch)?TRACKER_NEWARRAY_SIG:NULL,1556&new_image,1557&new_length,1558&my_crw_fatal_error_handler,1559&class_set_methods);15601561if ( new_length > 0 ) {1562unsigned char *jvmti_space;15631564LOG2("cbClassFileLoadHook DID inject this class", classname);1565jvmti_space = (unsigned char *)jvmtiAllocate((jint)new_length);1566(void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);1567*new_class_data_len = (jint)new_length;1568*new_class_data = jvmti_space; /* VM will deallocate */1569} else {1570LOG2("cbClassFileLoadHook DID NOT inject this class", classname);1571*new_class_data_len = 0;1572*new_class_data = NULL;1573}1574if ( new_image != NULL ) {1575(void)free((void*)new_image); /* Free malloc() space with free() */1576}1577}1578(void)free((void*)classname);1579} rawMonitorExit(gdata->data_access_lock);1580} END_CALLBACK();1581}15821583/* JVMTI_EVENT_CLASS_LOAD */1584static void JNICALL1585cbClassLoad(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass)1586{15871588/* WARNING: This MAY be called before VM_INIT. */15891590LOG("cbClassLoad");15911592BEGIN_CALLBACK() {1593rawMonitorEnter(gdata->data_access_lock); {15941595WITH_LOCAL_REFS(env, 1) {1596jobject loader;15971598loader = getClassLoader(klass);1599event_class_load(env, thread, klass, loader);1600} END_WITH_LOCAL_REFS;16011602} rawMonitorExit(gdata->data_access_lock);1603} END_CALLBACK();1604}16051606/* JVMTI_EVENT_CLASS_PREPARE */1607static void JNICALL1608cbClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass)1609{16101611/* WARNING: This will be called before VM_INIT. */16121613LOG("cbClassPrepare");16141615BEGIN_CALLBACK() {1616rawMonitorEnter(gdata->data_access_lock); {16171618WITH_LOCAL_REFS(env, 1) {1619jobject loader;16201621loader = NULL;1622loader = getClassLoader(klass);1623event_class_prepare(env, thread, klass, loader);1624} END_WITH_LOCAL_REFS;16251626} rawMonitorExit(gdata->data_access_lock);1627} END_CALLBACK();16281629}16301631/* JVMTI_EVENT_DATA_DUMP_REQUEST */1632static void JNICALL1633cbDataDumpRequest(jvmtiEnv *jvmti)1634{1635jboolean need_to_dump;16361637LOG("cbDataDumpRequest");16381639BEGIN_CALLBACK() {1640need_to_dump = JNI_FALSE;1641rawMonitorEnter(gdata->dump_lock); {1642if (!gdata->dump_in_process) {1643need_to_dump = JNI_TRUE;1644gdata->dump_in_process = JNI_TRUE;1645}1646} rawMonitorExit(gdata->dump_lock);16471648if (need_to_dump) {1649dump_all_data(getEnv());16501651rawMonitorEnter(gdata->dump_lock); {1652gdata->dump_in_process = JNI_FALSE;1653} rawMonitorExit(gdata->dump_lock);16541655if (gdata->cpu_sampling && !gdata->jvm_shut_down) {1656cpu_sample_on(NULL, 0); /* resume sampling */1657}1658}1659} END_CALLBACK();16601661}16621663/* JVMTI_EVENT_EXCEPTION_CATCH */1664static void JNICALL1665cbExceptionCatch(jvmtiEnv *jvmti, JNIEnv* env,1666jthread thread, jmethodID method, jlocation location,1667jobject exception)1668{1669LOG("cbExceptionCatch");16701671BEGIN_CALLBACK() {1672event_exception_catch(env, thread, method, location, exception);1673} END_CALLBACK();1674}16751676/* JVMTI_EVENT_MONITOR_WAIT */1677static void JNICALL1678cbMonitorWait(jvmtiEnv *jvmti, JNIEnv* env,1679jthread thread, jobject object, jlong timeout)1680{1681LOG("cbMonitorWait");16821683BEGIN_CALLBACK() {1684monitor_wait_event(env, thread, object, timeout);1685} END_CALLBACK();1686}16871688/* JVMTI_EVENT_MONITOR_WAITED */1689static void JNICALL1690cbMonitorWaited(jvmtiEnv *jvmti, JNIEnv* env,1691jthread thread, jobject object, jboolean timed_out)1692{1693LOG("cbMonitorWaited");16941695BEGIN_CALLBACK() {1696monitor_waited_event(env, thread, object, timed_out);1697} END_CALLBACK();1698}16991700/* JVMTI_EVENT_MONITOR_CONTENDED_ENTER */1701static void JNICALL1702cbMonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv* env,1703jthread thread, jobject object)1704{1705LOG("cbMonitorContendedEnter");17061707BEGIN_CALLBACK() {1708monitor_contended_enter_event(env, thread, object);1709} END_CALLBACK();1710}17111712/* JVMTI_EVENT_MONITOR_CONTENDED_ENTERED */1713static void JNICALL1714cbMonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* env,1715jthread thread, jobject object)1716{1717LOG("cbMonitorContendedEntered");17181719BEGIN_CALLBACK() {1720monitor_contended_entered_event(env, thread, object);1721} END_CALLBACK();1722}17231724/* JVMTI_EVENT_GARBAGE_COLLECTION_START */1725static void JNICALL1726cbGarbageCollectionStart(jvmtiEnv *jvmti)1727{1728LOG("cbGarbageCollectionStart");17291730/* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit1731* are allowed here (see the JVMTI Spec).1732*/17331734gdata->gc_start_time = md_get_timemillis();1735}17361737/* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */1738static void JNICALL1739cbGarbageCollectionFinish(jvmtiEnv *jvmti)1740{1741LOG("cbGarbageCollectionFinish");17421743/* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit1744* are allowed here (see the JVMTI Spec).1745*/17461747if ( gdata->gc_start_time != -1L ) {1748gdata->time_in_gc += (md_get_timemillis() - gdata->gc_start_time);1749gdata->gc_start_time = -1L;1750}17511752/* Increment gc_finish counter, notify watcher thread */1753rawMonitorEnter(gdata->gc_finish_lock); {1754/* If VM_DEATH is trying to shut it down, don't do anything at all.1755* Never send notify if VM_DEATH wants the watcher thread to quit.1756*/1757if ( gdata->gc_finish_active ) {1758gdata->gc_finish++;1759rawMonitorNotifyAll(gdata->gc_finish_lock);1760}1761} rawMonitorExit(gdata->gc_finish_lock);1762}17631764/* JVMTI_EVENT_OBJECT_FREE */1765static void JNICALL1766cbObjectFree(jvmtiEnv *jvmti, jlong tag)1767{1768LOG3("cbObjectFree", "tag", (int)tag);17691770/* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit1771* are allowed here (see the JVMTI Spec).1772*/17731774HPROF_ASSERT(tag!=(jlong)0);1775rawMonitorEnter(gdata->object_free_lock); {1776if ( !gdata->jvm_shut_down ) {1777Stack *stack;17781779stack = gdata->object_free_stack;1780if ( stack == NULL ) {1781gdata->object_free_stack = stack_init(512, 512, sizeof(jlong));1782stack = gdata->object_free_stack;1783}1784stack_push(stack, (void*)&tag);1785}1786} rawMonitorExit(gdata->object_free_lock);1787}17881789static void1790set_callbacks(jboolean on)1791{1792jvmtiEventCallbacks callbacks;17931794(void)memset(&callbacks,0,sizeof(callbacks));1795if ( ! on ) {1796setEventCallbacks(&callbacks);1797return;1798}17991800/* JVMTI_EVENT_VM_INIT */1801callbacks.VMInit = &cbVMInit;1802/* JVMTI_EVENT_VM_DEATH */1803callbacks.VMDeath = &cbVMDeath;1804/* JVMTI_EVENT_THREAD_START */1805callbacks.ThreadStart = &cbThreadStart;1806/* JVMTI_EVENT_THREAD_END */1807callbacks.ThreadEnd = &cbThreadEnd;1808/* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */1809callbacks.ClassFileLoadHook = &cbClassFileLoadHook;1810/* JVMTI_EVENT_CLASS_LOAD */1811callbacks.ClassLoad = &cbClassLoad;1812/* JVMTI_EVENT_CLASS_PREPARE */1813callbacks.ClassPrepare = &cbClassPrepare;1814/* JVMTI_EVENT_DATA_DUMP_REQUEST */1815callbacks.DataDumpRequest = &cbDataDumpRequest;1816/* JVMTI_EVENT_EXCEPTION_CATCH */1817callbacks.ExceptionCatch = &cbExceptionCatch;1818/* JVMTI_EVENT_MONITOR_WAIT */1819callbacks.MonitorWait = &cbMonitorWait;1820/* JVMTI_EVENT_MONITOR_WAITED */1821callbacks.MonitorWaited = &cbMonitorWaited;1822/* JVMTI_EVENT_MONITOR_CONTENDED_ENTER */1823callbacks.MonitorContendedEnter = &cbMonitorContendedEnter;1824/* JVMTI_EVENT_MONITOR_CONTENDED_ENTERED */1825callbacks.MonitorContendedEntered = &cbMonitorContendedEntered;1826/* JVMTI_EVENT_GARBAGE_COLLECTION_START */1827callbacks.GarbageCollectionStart = &cbGarbageCollectionStart;1828/* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */1829callbacks.GarbageCollectionFinish = &cbGarbageCollectionFinish;1830/* JVMTI_EVENT_OBJECT_FREE */1831callbacks.ObjectFree = &cbObjectFree;18321833setEventCallbacks(&callbacks);18341835}18361837static void1838getCapabilities(void)1839{1840jvmtiCapabilities needed_capabilities;1841jvmtiCapabilities potential_capabilities;18421843/* Fill in ones that we must have */1844(void)memset(&needed_capabilities,0,sizeof(needed_capabilities));1845needed_capabilities.can_generate_garbage_collection_events = 1;1846needed_capabilities.can_tag_objects = 1;1847if (gdata->bci) {1848needed_capabilities.can_generate_all_class_hook_events = 1;1849}1850if (gdata->obj_watch) {1851needed_capabilities.can_generate_object_free_events = 1;1852}1853if (gdata->cpu_timing || gdata->cpu_sampling) {1854#if 0 /* Not needed until we call JVMTI for CpuTime */1855needed_capabilities.can_get_thread_cpu_time = 1;1856needed_capabilities.can_get_current_thread_cpu_time = 1;1857#endif1858needed_capabilities.can_generate_exception_events = 1;1859}1860if (gdata->monitor_tracing) {1861#if 0 /* Not needed until we call JVMTI for CpuTime */1862needed_capabilities.can_get_thread_cpu_time = 1;1863needed_capabilities.can_get_current_thread_cpu_time = 1;1864#endif1865needed_capabilities.can_get_owned_monitor_info = 1;1866needed_capabilities.can_get_current_contended_monitor = 1;1867needed_capabilities.can_get_monitor_info = 1;1868needed_capabilities.can_generate_monitor_events = 1;1869}18701871/* Get potential capabilities */1872getPotentialCapabilities(&potential_capabilities);18731874/* Some capabilities would be nicer to have */1875needed_capabilities.can_get_source_file_name =1876potential_capabilities.can_get_source_file_name;1877needed_capabilities.can_get_line_numbers =1878potential_capabilities.can_get_line_numbers;18791880/* Add the capabilities */1881addCapabilities(&needed_capabilities);18821883}18841885/* Dynamic library loading */1886static void *1887load_library(char *name)1888{1889char lname[FILENAME_MAX+1];1890char err_buf[256+FILENAME_MAX+1];1891char *boot_path;1892void *handle;18931894handle = NULL;18951896/* The library may be located in different ways, try both, but1897* if it comes from outside the SDK/jre it isn't ours.1898*/1899getSystemProperty("sun.boot.library.path", &boot_path);1900md_build_library_name(lname, FILENAME_MAX, boot_path, name);1901if ( strlen(lname) == 0 ) {1902HPROF_ERROR(JNI_TRUE, "Could not find library");1903}1904jvmtiDeallocate(boot_path);1905handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));1906if ( handle == NULL ) {1907/* This may be necessary on Windows. */1908md_build_library_name(lname, FILENAME_MAX, "", name);1909if ( strlen(lname) == 0 ) {1910HPROF_ERROR(JNI_TRUE, "Could not find library");1911}1912handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));1913if ( handle == NULL ) {1914HPROF_ERROR(JNI_TRUE, err_buf);1915}1916}1917return handle;1918}19191920/* Lookup dynamic function pointer in shared library */1921static void *1922lookup_library_symbol(void *library, char **symbols, int nsymbols)1923{1924void *addr;1925int i;19261927addr = NULL;1928for( i = 0 ; i < nsymbols; i++ ) {1929addr = md_find_library_entry(library, symbols[i]);1930if ( addr != NULL ) {1931break;1932}1933}1934if ( addr == NULL ) {1935char errmsg[256];19361937(void)md_snprintf(errmsg, sizeof(errmsg),1938"Cannot find library symbol '%s'", symbols[0]);1939HPROF_ERROR(JNI_TRUE, errmsg);1940}1941return addr;1942}19431944/* ------------------------------------------------------------------- */1945/* The OnLoad interface */19461947JNIEXPORT jint JNICALL1948Agent_OnLoad(JavaVM *vm, char *options, void *reserved)1949{1950char *boot_path = NULL;1951char npt_lib[JVM_MAXPATHLEN];19521953/* See if it's already loaded */1954if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) {1955HPROF_ERROR(JNI_TRUE, "Cannot load this JVM TI agent twice, check your java command line for duplicate hprof options.");1956return JNI_ERR;1957}19581959gdata = get_gdata();19601961gdata->isLoaded = JNI_TRUE;19621963error_setup();19641965LOG2("Agent_OnLoad", "gdata setup");19661967gdata->jvm = vm;19681969/* Get the JVMTI environment */1970getJvmti();19711972#ifndef SKIP_NPT1973getSystemProperty("sun.boot.library.path", &boot_path);1974/* Load in NPT library for character conversions */1975md_build_library_name(npt_lib, sizeof(npt_lib), boot_path, NPT_LIBNAME);1976if ( strlen(npt_lib) == 0 ) {1977HPROF_ERROR(JNI_TRUE, "Could not find npt library");1978}1979jvmtiDeallocate(boot_path);1980NPT_INITIALIZE(npt_lib, &(gdata->npt), NPT_VERSION, NULL);1981if ( gdata->npt == NULL ) {1982HPROF_ERROR(JNI_TRUE, "Cannot load npt library");1983}1984gdata->npt->utf = (gdata->npt->utfInitialize)(NULL);1985if ( gdata->npt->utf == NULL ) {1986HPROF_ERROR(JNI_TRUE, "Cannot initialize npt utf functions");1987}1988#endif19891990/* Lock needed to protect debug_malloc() code, which is not MT safe */1991#ifdef DEBUG1992gdata->debug_malloc_lock = createRawMonitor("HPROF debug_malloc lock");1993#endif19941995parse_options(options);19961997LOG2("Agent_OnLoad", "Has jvmtiEnv and options parsed");19981999/* Initialize machine dependent code (micro state accounting) */2000md_init();20012002string_init(); /* Table index values look like: 0x10000000 */20032004class_init(); /* Table index values look like: 0x20000000 */2005tls_init(); /* Table index values look like: 0x30000000 */2006trace_init(); /* Table index values look like: 0x40000000 */2007object_init(); /* Table index values look like: 0x50000000 */20082009site_init(); /* Table index values look like: 0x60000000 */2010frame_init(); /* Table index values look like: 0x70000000 */2011monitor_init(); /* Table index values look like: 0x80000000 */2012loader_init(); /* Table index values look like: 0x90000000 */20132014LOG2("Agent_OnLoad", "Tables initialized");20152016if ( gdata->pause ) {2017error_do_pause();2018}20192020getCapabilities();20212022/* Set the JVMTI callback functions (do this only once)*/2023set_callbacks(JNI_TRUE);20242025/* Create basic locks */2026gdata->dump_lock = createRawMonitor("HPROF dump lock");2027gdata->data_access_lock = createRawMonitor("HPROF data access lock");2028gdata->callbackLock = createRawMonitor("HPROF callback lock");2029gdata->callbackBlock = createRawMonitor("HPROF callback block");2030gdata->object_free_lock = createRawMonitor("HPROF object free lock");2031gdata->gc_finish_lock = createRawMonitor("HPROF gc_finish lock");20322033/* Set Onload events mode. */2034setup_event_mode(JNI_TRUE, JVMTI_ENABLE);20352036LOG2("Agent_OnLoad", "JVMTI capabilities, callbacks and initial notifications setup");20372038/* Used in VM_DEATH to wait for callbacks to complete */2039gdata->jvm_initializing = JNI_FALSE;2040gdata->jvm_initialized = JNI_FALSE;2041gdata->vm_death_callback_active = JNI_FALSE;2042gdata->active_callbacks = 0;20432044/* Write the header information */2045io_setup();20462047/* We sample the start time now so that the time increments can be2048* placed in the various heap dump segments in micro seconds.2049*/2050gdata->micro_sec_ticks = md_get_microsecs();20512052/* Load java_crw_demo library and find function "java_crw_demo" */2053if ( gdata->bci ) {20542055/* Load the library or get the handle to it */2056gdata->java_crw_demo_library = load_library("java_crw_demo");20572058{ /* "java_crw_demo" */2059static char *symbols[] = JAVA_CRW_DEMO_SYMBOLS;2060gdata->java_crw_demo_function =2061lookup_library_symbol(gdata->java_crw_demo_library,2062symbols, (int)(sizeof(symbols)/sizeof(char*)));2063}2064{ /* "java_crw_demo_classname" */2065static char *symbols[] = JAVA_CRW_DEMO_CLASSNAME_SYMBOLS;2066gdata->java_crw_demo_classname_function =2067lookup_library_symbol(gdata->java_crw_demo_library,2068symbols, (int)(sizeof(symbols)/sizeof(char*)));2069}2070}20712072return JNI_OK;2073}20742075JNIEXPORT void JNICALL2076Agent_OnUnload(JavaVM *vm)2077{2078Stack *stack;20792080LOG("Agent_OnUnload");20812082gdata->isLoaded = JNI_FALSE;20832084stack = gdata->object_free_stack;2085gdata->object_free_stack = NULL;2086if ( stack != NULL ) {2087stack_term(stack);2088}20892090io_cleanup();2091loader_cleanup();2092tls_cleanup();2093monitor_cleanup();2094trace_cleanup();2095site_cleanup();2096object_cleanup();2097frame_cleanup();2098class_cleanup();2099string_cleanup();21002101/* Deallocate any memory in gdata */2102if ( gdata->net_hostname != NULL ) {2103HPROF_FREE(gdata->net_hostname);2104}2105if ( gdata->utf8_output_filename != NULL ) {2106HPROF_FREE(gdata->utf8_output_filename);2107}2108if ( gdata->output_filename != NULL ) {2109HPROF_FREE(gdata->output_filename);2110}2111if ( gdata->heapfilename != NULL ) {2112HPROF_FREE(gdata->heapfilename);2113}2114if ( gdata->checkfilename != NULL ) {2115HPROF_FREE(gdata->checkfilename);2116}2117if ( gdata->options != NULL ) {2118HPROF_FREE(gdata->options);2119}21202121/* Verify all allocated memory has been taken care of. */2122malloc_police();21232124/* Cleanup is hard to do when other threads might still be running2125* so we skip destroying some raw monitors which still might be in use2126* and we skip disposal of the jvmtiEnv* which might still be needed.2127* Only raw monitors that could be held by other threads are left2128* alone. So we explicitly do NOT do this:2129* destroyRawMonitor(gdata->callbackLock);2130* destroyRawMonitor(gdata->callbackBlock);2131* destroyRawMonitor(gdata->gc_finish_lock);2132* destroyRawMonitor(gdata->object_free_lock);2133* destroyRawMonitor(gdata->listener_loop_lock);2134* destroyRawMonitor(gdata->cpu_loop_lock);2135* disposeEnvironment();2136* gdata->jvmti = NULL;2137*/21382139/* Destroy basic locks */2140destroyRawMonitor(gdata->dump_lock);2141gdata->dump_lock = NULL;2142destroyRawMonitor(gdata->data_access_lock);2143gdata->data_access_lock = NULL;2144if ( gdata->cpu_sample_lock != NULL ) {2145destroyRawMonitor(gdata->cpu_sample_lock);2146gdata->cpu_sample_lock = NULL;2147}2148#ifdef DEBUG2149destroyRawMonitor(gdata->debug_malloc_lock);2150gdata->debug_malloc_lock = NULL;2151#endif21522153/* Unload java_crw_demo library */2154if ( gdata->bci && gdata->java_crw_demo_library != NULL ) {2155md_unload_library(gdata->java_crw_demo_library);2156gdata->java_crw_demo_library = NULL;2157}21582159/* You would think you could clear out gdata and set it to NULL, but2160* turns out that isn't a good idea. Some of the threads could be2161* blocked inside the CALLBACK*() macros, where they got blocked up2162* waiting for the VM_DEATH callback to complete. They only have2163* some raw monitor actions to do, but they need access to gdata to do it.2164* So do not do this:2165* (void)memset(gdata, 0, sizeof(GlobalData));2166* gdata = NULL;2167*/2168}216921702171