/* Worker thread that waits for garbage collections */ static void JNICALL worker(jvmtiEnv* jvmti, JNIEnv* jni, void *p) { jvmtiError err; stdout_message("GC worker started...\n"); for (;;) { err = (*jvmti)->RawMonitorEnter(jvmti, lock); check_jvmti_error(jvmti, err, "raw monitor enter"); while (gc_count == 0) { err = (*jvmti)->RawMonitorWait(jvmti, lock, 0); if (err != JVMTI_ERROR_NONE) { err = (*jvmti)->RawMonitorExit(jvmti, lock); check_jvmti_error(jvmti, err, "raw monitor wait"); return; } } gc_count = 0; err = (*jvmti)->RawMonitorExit(jvmti, lock); check_jvmti_error(jvmti, err, "raw monitor exit"); /* Perform arbitrary JVMTI/JNI work here to do post-GC cleanup */ stdout_message("post-GarbageCollectionFinish actions...\n"); } }
/* VM initialization and VM death calls to Agent */ Agent::Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { stdout_message("Agent created..\n"); stdout_message("VMInit...\n"); /* Start monitor list */ monitor_count = 0; monitor_list_size = initial_monitor_list_size; monitor_list = (Monitor**) malloc(monitor_list_size*(int)sizeof(Monitor*)); }
/* VM initialization and VM death calls to Agent */ Agent::Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { jvmtiError err; stdout_message("Agent created..\n"); stdout_message("VMInit...\n"); /* Create a Monitor lock to use */ err = jvmti->CreateRawMonitor("waiters Agent lock", &lock); check_jvmti_error(jvmti, err, "create raw monitor"); /* Start monitor list */ monitor_count = 0; monitor_list = (Monitor**)malloc((int)sizeof(Monitor*)); }
static bool display_log_line(int fd) { log_level level; wchar_t *module, *msg; level = ctl_recv_int(fd); if (check_error()) { return false; } module = ctl_recv_wchars(fd, NULL); if (!module) { return false; } msg = ctl_recv_wchars(fd, NULL); if (!msg) { return false; } stdout_message(level, module, msg); /* Force a fflush in case with are redirected to a file */ fflush(stdout); free(module); free(msg); return true; }
/* Callback for JVMTI_EVENT_VM_INIT */ static void JNICALL cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { enter_critical_section(jvmti); { char tname[MAX_THREAD_NAME_LENGTH]; static jvmtiEvent events[] = { JVMTI_EVENT_THREAD_START, JVMTI_EVENT_THREAD_END }; int i; /* The VM has started. */ get_thread_name(jvmti, thread, tname, sizeof(tname)); stdout_message("VMInit %s\n", tname); /* The VM is now initialized, at this time we make our requests * for additional events. */ for( i=0; i < (int)(sizeof(events)/sizeof(jvmtiEvent)); i++) { jvmtiError error; /* Setup event notification modes */ error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, events[i], (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); } } exit_critical_section(jvmti); }
void Agent::vm_death(jvmtiEnv *jvmti, JNIEnv *env) { /* Delete all Monitors we allocated */ for ( int i = 0; i < (int)monitor_count; i++ ) { delete monitor_list[i]; } free(monitor_list); /* Print death message */ stdout_message("VMDeath...\n"); }
/* Callback for JVMTI_EVENT_VM_INIT */ static void JNICALL vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { jvmtiError err; stdout_message("VMInit...\n"); err = (*jvmti)->RunAgentThread(jvmti, alloc_thread(env), &worker, NULL, JVMTI_THREAD_MAX_PRIORITY); check_jvmti_error(jvmti, err, "running agent thread"); }
/* Create major.minor.micro version string */ static void version_check(jint cver, jint rver) { jint cmajor, cminor, cmicro; jint rmajor, rminor, rmicro; cmajor = (cver & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR; cminor = (cver & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR; cmicro = (cver & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO; rmajor = (rver & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR; rminor = (rver & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR; rmicro = (rver & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO; stdout_message("Compile Time JVMTI Version: %d.%d.%d (0x%08x)\n", cmajor, cminor, cmicro, cver); stdout_message("Run Time JVMTI Version: %d.%d.%d (0x%08x)\n", rmajor, rminor, rmicro, rver); if ( (cmajor > rmajor) || (cmajor == rmajor && cminor > rminor) ) { fatal_error( "ERROR: Compile Time JVMTI and Run Time JVMTI are incompatible\n"); } }
/* Callback for JVMTI_EVENT_THREAD_END */ static void JNICALL cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { enter_critical_section(jvmti); { /* It's possible we get here right after VmDeath event, be careful */ if ( !gdata->vm_is_dead ) { char tname[MAX_THREAD_NAME_LENGTH]; get_thread_name(jvmti, thread, tname, sizeof(tname)); stdout_message("ThreadEnd %s\n", tname); } } exit_critical_section(jvmti); }
/* Callback for JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */ static void JNICALL gc_finish(jvmtiEnv* jvmti_env) { jvmtiError err; stdout_message("GarbageCollectionFinish...\n"); err = (*jvmti)->RawMonitorEnter(jvmti, lock); check_jvmti_error(jvmti, err, "raw monitor enter"); gc_count++; err = (*jvmti)->RawMonitorNotify(jvmti, lock); check_jvmti_error(jvmti, err, "raw monitor notify"); err = (*jvmti)->RawMonitorExit(jvmti, lock); check_jvmti_error(jvmti, err, "raw monitor exit"); }
void Agent::vm_death(jvmtiEnv *jvmti, JNIEnv *env) { jvmtiError err; /* Delete all Monitors we allocated */ for ( int i = 0; i < (int)monitor_count; i++ ) { delete monitor_list[i]; } free(monitor_list); /* Destroy the Monitor lock to use */ err = jvmti->DestroyRawMonitor(lock); check_jvmti_error(jvmti, err, "destroy raw monitor"); /* Print death message */ stdout_message("VMDeath...\n"); }
/* Parse the options for this heapTracker agent */ static void parse_agent_options(char *options) { #define MAX_TOKEN_LENGTH 16 char token[MAX_TOKEN_LENGTH]; char *next; /* Defaults */ gdata->maxDump = 20; /* Parse options and set flags in gdata */ if ( options==NULL ) { return; } /* Get the first token from the options string. */ next = get_token(options, ",=", token, (int)sizeof(token)); /* While not at the end of the options string, process this option. */ while ( next != NULL ) { if ( strcmp(token,"help")==0 ) { stdout_message("The heapTracker JVMTI demo agent\n"); stdout_message("\n"); stdout_message(" java -agent:heapTracker[=options] ...\n"); stdout_message("\n"); stdout_message("The options are comma separated:\n"); stdout_message("\t help\t\t\t Print help information\n"); stdout_message("\t maxDump=n\t\t\t How many TraceInfo's to dump\n"); stdout_message("\n"); exit(0); } else if ( strcmp(token,"maxDump")==0 ) { char number[MAX_TOKEN_LENGTH]; next = get_token(next, ",=", number, (int)sizeof(number)); if ( next == NULL ) { fatal_error("ERROR: Cannot parse maxDump=number: %s\n", options); } gdata->maxDump = atoi(number); } else if ( token[0]!=0 ) { /* We got a non-empty token and we don't know what it is. */ fatal_error("ERROR: Unknown option: %s\n", token); } /* Get the next token (returns NULL if there are no more) */ next = get_token(next, ",=", token, (int)sizeof(token)); } }
/* Callback for JVMTI_EVENT_VM_START */ static void JNICALL cbVMStart(jvmtiEnv *jvmti, JNIEnv *env) { enter_critical_section(jvmti); { jclass klass; jfieldID field; int rc; /* Java Native Methods for class */ static JNINativeMethod registry[2] = { { STRING(MTRACE_native_entry), "(Ljava/lang/Object;II)V", (void*)&MTRACE_native_entry }, { STRING(MTRACE_native_exit), "(Ljava/lang/Object;II)V", (void*)&MTRACE_native_exit } }; /* The VM has started. */ stdout_message("VMStart\n"); /* Register Natives for class whose methods we use */ klass = (*env)->FindClass(env, STRING(MTRACE_class)); if ( klass == NULL ) { fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", STRING(MTRACE_class)); } rc = (*env)->RegisterNatives(env, klass, registry, 2); if ( rc != 0 ) { fatal_error("ERROR: JNI: Cannot register native methods for %s\n", STRING(MTRACE_class)); } /* Engage calls. */ field = (*env)->GetStaticFieldID(env, klass, STRING(MTRACE_engaged), "I"); if ( field == NULL ) { fatal_error("ERROR: JNI: Cannot get field from %s\n", STRING(MTRACE_class)); } (*env)->SetStaticIntField(env, klass, field, 1); /* Indicate VM has started */ gdata->vm_is_started = JNI_TRUE; } exit_critical_section(jvmti); }
/* Given a jvmtiEnv* and jthread, find the Thread instance */ Thread * Agent::get_thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { jvmtiError err; Thread *t; /* This should always be in the Thread Local Storage */ t = NULL; err = jvmti->GetThreadLocalStorage(thread, (void**)&t); check_jvmti_error(jvmti, err, "get thread local storage"); if ( t == NULL ) { /* This jthread has never been seen before? */ stdout_message("WARNING: Never before seen jthread?\n"); t = new Thread(jvmti, env, thread); err = jvmti->SetThreadLocalStorage(thread, (const void*)t); check_jvmti_error(jvmti, err, "set thread local storage"); } return t; }
/* Callback for JVMTI_EVENT_VM_DEATH */ static void JNICALL cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env) { enter_critical_section(jvmti); { jclass klass; jfieldID field; /* The VM has died. */ stdout_message("VMDeath\n"); /* Disengage calls in MINST_class. */ klass = (*env)->FindClass(env, STRING(MINST_class)); if ( klass == NULL ) { fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", STRING(MINST_class)); } field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I"); if ( field == NULL ) { fatal_error("ERROR: JNI: Cannot get field from %s\n", STRING(MINST_class)); } (*env)->SetStaticIntField(env, klass, field, -1); /* The critical section here is important to hold back the VM death * until all other callbacks have completed. */ /* Since this critical section could be holding up other threads * in other event callbacks, we need to indicate that the VM is * dead so that the other callbacks can short circuit their work. * We don't expect any further events after VmDeath but we do need * to be careful that existing threads might be in our own agent * callback code. */ gdata->vm_is_dead = JNI_TRUE; } exit_critical_section(jvmti); }
/* Print the information */ static void printTraceInfo(jvmtiEnv *jvmti, int index, TraceInfo* tinfo) { if ( tinfo == NULL ) { fatal_error("%d: NULL ENTRY ERROR\n", index); return; } stdout_message("%2d: %7d bytes %5d objects %5d live %s", index, (int)tinfo->totalSpace, tinfo->totalCount, tinfo->useCount, flavorDesc[tinfo->trace.flavor]); if ( tinfo->trace.nframes > 0 ) { int i; int fcount; fcount = 0; stdout_message(" stack=("); for ( i = 0 ; i < tinfo->trace.nframes ; i++ ) { char buf[4096]; frameToString(jvmti, buf, (int)sizeof(buf), tinfo->trace.frames+i); if ( buf[0] == 0 ) { continue; /* Skip the ones that are from Tracker class */ } fcount++; stdout_message("%s", buf); if ( i < (tinfo->trace.nframes-1) ) { stdout_message(","); } } stdout_message(") nframes=%d\n", fcount); } else { stdout_message(" stack=<empty>\n"); } }
Monitor::~Monitor() { stdout_message("Monitor %s summary: %d contends, %d waits, %d timeouts\n", name, contends, waits, timeouts); }
Agent::~Agent() { stdout_message("Agent reclaimed..\n"); }
Thread::~Thread() { /* Send out summary message */ stdout_message("Thread %s summary: %d waits plus %d contended\n", name, waits, contends); }
/* Callback for JVMTI_EVENT_DATA_DUMP_REQUEST (Ctrl-\ or at exit) */ static void JNICALL dataDumpRequest(jvmtiEnv *jvmti) { enterAgentMonitor(jvmti); { if ( !gdata->vmDeathCalled && !gdata->dumpInProgress ) { jvmtiHeapCallbacks heapCallbacks; ClassDetails *details; jvmtiError err; jclass *classes; jint totalCount; jint count; jint i; gdata->dumpInProgress = JNI_TRUE; /* Get all the loaded classes */ err = (*jvmti)->GetLoadedClasses(jvmti, &count, &classes); check_jvmti_error(jvmti, err, "get loaded classes"); /* Setup an area to hold details about these classes */ details = (ClassDetails*)calloc(sizeof(ClassDetails), count); if ( details == NULL ) { fatal_error("ERROR: Ran out of malloc space\n"); } for ( i = 0 ; i < count ; i++ ) { char *sig; /* Get and save the class signature */ err = (*jvmti)->GetClassSignature(jvmti, classes[i], &sig, NULL); check_jvmti_error(jvmti, err, "get class signature"); if ( sig == NULL ) { fatal_error("ERROR: No class signature found\n"); } details[i].signature = strdup(sig); deallocate(jvmti, sig); /* Tag this jclass */ err = (*jvmti)->SetTag(jvmti, classes[i], (jlong)(ptrdiff_t)(void*)(&details[i])); check_jvmti_error(jvmti, err, "set object tag"); } /* Iterate through the heap and count up uses of jclass */ (void)memset(&heapCallbacks, 0, sizeof(heapCallbacks)); heapCallbacks.heap_iteration_callback = &cbHeapObject; totalCount = 0; err = (*jvmti)->IterateThroughHeap(jvmti, JVMTI_HEAP_FILTER_CLASS_UNTAGGED, NULL, &heapCallbacks, (const void *)&totalCount); check_jvmti_error(jvmti, err, "iterate through heap"); /* Remove tags */ for ( i = 0 ; i < count ; i++ ) { /* Un-Tag this jclass */ err = (*jvmti)->SetTag(jvmti, classes[i], (jlong)0); check_jvmti_error(jvmti, err, "set object tag"); } /* Sort details by space used */ qsort(details, count, sizeof(ClassDetails), &compareDetails); /* Print out sorted table */ stdout_message("Heap View, Total of %d objects found.\n\n", totalCount); stdout_message("Space Count Class Signature\n"); stdout_message("---------- ---------- ----------------------\n"); for ( i = 0 ; i < count ; i++ ) { if ( details[i].space == 0 || i > 20 ) { break; } stdout_message("%10d %10d %s\n", details[i].space, details[i].count, details[i].signature); } stdout_message("---------- ---------- ----------------------\n\n"); /* Free up all allocated space */ deallocate(jvmti, classes); for ( i = 0 ; i < count ; i++ ) { if ( details[i].signature != NULL ) { free(details[i].signature); } } free(details); gdata->dumpInProgress = JNI_FALSE; } } exitAgentMonitor(jvmti); }
/* Callback for JVMTI_EVENT_VM_DEATH */ static void JNICALL cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env) { enter_critical_section(jvmti); { jclass klass; jfieldID field; /* The VM has died. */ stdout_message("VMDeath\n"); /* Disengage calls in MTRACE_class. */ klass = (*env)->FindClass(env, STRING(MTRACE_class)); if ( klass == NULL ) { fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", STRING(MTRACE_class)); } field = (*env)->GetStaticFieldID(env, klass, STRING(MTRACE_engaged), "I"); if ( field == NULL ) { fatal_error("ERROR: JNI: Cannot get field from %s\n", STRING(MTRACE_class)); } (*env)->SetStaticIntField(env, klass, field, 0); /* The critical section here is important to hold back the VM death * until all other callbacks have completed. */ /* Since this critical section could be holding up other threads * in other event callbacks, we need to indicate that the VM is * dead so that the other callbacks can short circuit their work. * We don't expect any further events after VmDeath but we do need * to be careful that existing threads might be in our own agent * callback code. */ gdata->vm_is_dead = JNI_TRUE; /* Dump out stats */ stdout_message("Begin Class Stats\n"); if ( gdata->ccount > 0 ) { int cnum; /* Sort table (in place) by number of method calls into class. */ /* Note: Do not use this table after this qsort! */ qsort(gdata->classes, gdata->ccount, sizeof(ClassInfo), &class_compar); /* Dump out gdata->max_count most called classes */ for ( cnum=gdata->ccount-1 ; cnum >= 0 && cnum >= gdata->ccount - gdata->max_count; cnum-- ) { ClassInfo *cp; int mnum; cp = gdata->classes + cnum; stdout_message("Class %s %d calls\n", cp->name, cp->calls); if ( cp->calls==0 ) continue; /* Sort method table (in place) by number of method calls. */ /* Note: Do not use this table after this qsort! */ qsort(cp->methods, cp->mcount, sizeof(MethodInfo), &method_compar); for ( mnum=cp->mcount-1 ; mnum >= 0 ; mnum-- ) { MethodInfo *mp; mp = cp->methods + mnum; if ( mp->calls==0 ) continue; stdout_message("\tMethod %s %s %d calls %d returns\n", mp->name, mp->signature, mp->calls, mp->returns); } } } stdout_message("End Class Stats\n"); (void)fflush(stdout); } exit_critical_section(jvmti); }
/* Callback for JVMTI_EVENT_VM_DEATH */ static void JNICALL cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env) { jvmtiHeapCallbacks heapCallbacks; jvmtiError error; /* These are purposely done outside the critical section */ /* Force garbage collection now so we get our ObjectFree calls */ error = (*jvmti)->ForceGarbageCollection(jvmti); check_jvmti_error(jvmti, error, "Cannot force garbage collection"); /* Iterate through heap and find all objects */ (void)memset(&heapCallbacks, 0, sizeof(heapCallbacks)); heapCallbacks.heap_iteration_callback = &cbObjectSpaceCounter; error = (*jvmti)->IterateThroughHeap(jvmti, 0, NULL, &heapCallbacks, NULL); check_jvmti_error(jvmti, error, "Cannot iterate through heap"); /* Process VM Death */ enterCriticalSection(jvmti); { jclass klass; jfieldID field; jvmtiEventCallbacks callbacks; /* Disengage calls in HEAP_TRACKER_class. */ klass = (*env)->FindClass(env, STRING(HEAP_TRACKER_class)); if ( klass == NULL ) { fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", STRING(HEAP_TRACKER_class)); } field = (*env)->GetStaticFieldID(env, klass, STRING(HEAP_TRACKER_engaged), "I"); if ( field == NULL ) { fatal_error("ERROR: JNI: Cannot get field from %s\n", STRING(HEAP_TRACKER_class)); } (*env)->SetStaticIntField(env, klass, field, 0); /* The critical section here is important to hold back the VM death * until all other callbacks have completed. */ /* Clear out all callbacks. */ (void)memset(&callbacks,0, sizeof(callbacks)); error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks"); /* Since this critical section could be holding up other threads * in other event callbacks, we need to indicate that the VM is * dead so that the other callbacks can short circuit their work. * We don't expect an further events after VmDeath but we do need * to be careful that existing threads might be in our own agent * callback code. */ gdata->vmDead = JNI_TRUE; /* Dump all objects */ if ( gdata->traceInfoCount > 0 ) { TraceInfo **list; int count; int i; stdout_message("Dumping heap trace information\n"); /* Create single array of pointers to TraceInfo's, sort, and * print top gdata->maxDump top space users. */ list = (TraceInfo**)calloc(gdata->traceInfoCount, sizeof(TraceInfo*)); if ( list == NULL ) { fatal_error("ERROR: Ran out of malloc() space\n"); } count = 0; for ( i = 0 ; i < HASH_BUCKET_COUNT ; i++ ) { TraceInfo *tinfo; tinfo = gdata->hashBuckets[i]; while ( tinfo != NULL ) { if ( count < gdata->traceInfoCount ) { list[count++] = tinfo; } tinfo = tinfo->next; } } if ( count != gdata->traceInfoCount ) { fatal_error("ERROR: Count found by iterate doesn't match ours:" " count=%d != traceInfoCount==%d\n", count, gdata->traceInfoCount); } qsort(list, count, sizeof(TraceInfo*), &compareInfo); for ( i = 0 ; i < count ; i++ ) { if ( i >= gdata->maxDump ) { break; } printTraceInfo(jvmti, i+1, list[i]); } (void)free(list); } } exitCriticalSection(jvmti); }
/* Parse the options for this mtrace agent */ static void parse_agent_options(char *options) { char token[MAX_TOKEN_LENGTH]; char *next; gdata->max_count = 10; /* Default max=n */ /* Parse options and set flags in gdata */ if ( options==NULL ) { return; } /* Get the first token from the options string. */ next = get_token(options, ",=", token, sizeof(token)); /* While not at the end of the options string, process this option. */ while ( next != NULL ) { if ( strcmp(token,"help")==0 ) { stdout_message("The mtrace JVMTI demo agent\n"); stdout_message("\n"); stdout_message(" java -agent:mtrace[=options] ...\n"); stdout_message("\n"); stdout_message("The options are comma separated:\n"); stdout_message("\t help\t\t\t Print help information\n"); stdout_message("\t max=n\t\t Only list top n classes\n"); stdout_message("\t include=item\t\t Only these classes/methods\n"); stdout_message("\t exclude=item\t\t Exclude these classes/methods\n"); stdout_message("\n"); stdout_message("item\t Qualified class and/or method names\n"); stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n"); stdout_message("\n"); exit(0); } else if ( strcmp(token,"max")==0 ) { char number[MAX_TOKEN_LENGTH]; /* Get the numeric option */ next = get_token(next, ",=", number, (int)sizeof(number)); /* Check for token scan error */ if ( next==NULL ) { fatal_error("ERROR: max=n option error\n"); } /* Save numeric value */ gdata->max_count = atoi(number); } else if ( strcmp(token,"include")==0 ) { int used; int maxlen; maxlen = MAX_METHOD_NAME_LENGTH; if ( gdata->include == NULL ) { gdata->include = (char*)calloc(maxlen+1, 1); used = 0; } else { used = (int)strlen(gdata->include); gdata->include[used++] = ','; gdata->include[used] = 0; gdata->include = (char*) realloc((void*)gdata->include, used+maxlen+1); } if ( gdata->include == NULL ) { fatal_error("ERROR: Out of malloc memory\n"); } /* Add this item to the list */ next = get_token(next, ",=", gdata->include+used, maxlen); /* Check for token scan error */ if ( next==NULL ) { fatal_error("ERROR: include option error\n"); } } else if ( strcmp(token,"exclude")==0 ) { int used; int maxlen; maxlen = MAX_METHOD_NAME_LENGTH; if ( gdata->exclude == NULL ) { gdata->exclude = (char*)calloc(maxlen+1, 1); used = 0; } else { used = (int)strlen(gdata->exclude); gdata->exclude[used++] = ','; gdata->exclude[used] = 0; gdata->exclude = (char*) realloc((void*)gdata->exclude, used+maxlen+1); } if ( gdata->exclude == NULL ) { fatal_error("ERROR: Out of malloc memory\n"); } /* Add this item to the list */ next = get_token(next, ",=", gdata->exclude+used, maxlen); /* Check for token scan error */ if ( next==NULL ) { fatal_error("ERROR: exclude option error\n"); } } else if ( token[0]!=0 ) { /* We got a non-empty token and we don't know what it is. */ fatal_error("ERROR: Unknown option: %s\n", token); } /* Get the next token (returns NULL if there are no more) */ next = get_token(next, ",=", token, sizeof(token)); } }
/* Callback for JVMTI_EVENT_GARBAGE_COLLECTION_START */ static void JNICALL gc_start(jvmtiEnv* jvmti_env) { stdout_message("GarbageCollectionStart...\n"); }