Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_tls.c
38829 views
/*1* Copyright (c) 2003, 2011, 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#include "hprof.h"4142/* Thread Local Storage Table and method entry/exit handling. */4344/*45* The tls table items have a key of it's serial number, but may be46* searched via a walk of the table looking for a jthread match.47* This isn't a performance48* issue because the table index should normally be stored in the49* Thread Local Storage for the thread. The table is only searched50* when the jthread is seen before the Thread Local Storage is set51* (e.g. before VM_INIT or the ThreadStart).52* The key is only used when we need to lookup a tls table entry by53* way of it's serial number, which should be unique per thread.54*55* Each active thread that we have seen should have a unique TlsIndex56* which is an index into this table.57*58* For cpu=times, each table entry will have a stack to hold the method59* that have been called, effectively keeping an active stack trace60* for the thread. As each method exits, the statistics for the trace61* associated with the current stack contents is updated.62*63* For cpu=samples, each thread is checked to see if it's runnable,64* and not suspended, and has a stack associated with it, and then65* that stack trace is updated with an additional 'hit'.66*67* This file also contains the dump logic for owned monitors, and for68* threads.69*70*/7172/*73* Initial number of stack elements to track per thread. This74* value should be set to a reasonable guess as to the number of75* methods deep a thread calls. This stack doubles in size for each76* reallocation and does not shrink.77*/7879#define INITIAL_THREAD_STACK_LIMIT 648081typedef struct StackElement {82FrameIndex frame_index; /* Frame (method/location(-1)) */83jmethodID method; /* Method ID */84jlong method_start_time; /* method start time */85jlong time_in_callees; /* time in callees */86} StackElement;8788typedef struct TlsInfo {89jint sample_status; /* Thread status for cpu sampling */90jboolean agent_thread; /* Is thread our own agent thread? */91jthread globalref; /* Global reference for thread */92Stack *stack; /* Stack of StackElements entry/exit */93MonitorIndex monitor_index; /* last contended mon */94jint tracker_status; /* If we are inside Tracker class */95FrameIndex *frames_buffer; /* Buffer used to create TraceIndex */96jvmtiFrameInfo *jframes_buffer; /* Buffer used to create TraceIndex */97int buffer_depth; /* Frames allowed in buffer */98TraceIndex last_trace; /* Last trace for this thread */99ObjectIndex thread_object_index;/* If heap=dump */100jlong monitor_start_time; /* Start time for monitor */101jint in_heap_dump; /* If we are an object in the dump */102} TlsInfo;103104typedef struct SearchData {105JNIEnv *env;106jthread thread;107TlsIndex found;108} SearchData;109110typedef struct IterateInfo {111TlsIndex * ptls_index;112jthread * pthreads;113jint count;114} IterateInfo;115116typedef struct ThreadList {117jthread *threads;118SerialNumber *serial_nums;119TlsInfo **infos;120jint count;121JNIEnv *env;122} ThreadList;123124typedef struct SampleData {125ObjectIndex thread_object_index;126jint sample_status;127} SampleData;128129/* Private internal functions. */130131static SerialNumber132get_key(TlsIndex index)133{134SerialNumber *pkey;135int key_len;136137if ( index == 0 ) {138return 0;139}140pkey = NULL;141key_len = 0;142table_get_key(gdata->tls_table, index, (void**)&pkey, &key_len);143HPROF_ASSERT(pkey!=NULL);144HPROF_ASSERT(key_len==(int)sizeof(SerialNumber));145return *pkey;146}147148static TlsInfo *149get_info(TlsIndex index)150{151return (TlsInfo*)table_get_info(gdata->tls_table, index);152}153154static void155delete_globalref(JNIEnv *env, TlsInfo *info)156{157jthread ref;158159HPROF_ASSERT(env!=NULL);160HPROF_ASSERT(info!=NULL);161ref = info->globalref;162info->globalref = NULL;163if ( ref != NULL ) {164deleteWeakGlobalReference(env, ref);165}166}167168static void169clean_info(TlsInfo *info)170{171/* Free up any allocated space in this TlsInfo structure */172if ( info->stack != NULL ) {173stack_term(info->stack);174info->stack = NULL;175}176if ( info->frames_buffer != NULL ) {177HPROF_FREE(info->frames_buffer);178info->frames_buffer = NULL;179}180if ( info->jframes_buffer != NULL ) {181HPROF_FREE(info->jframes_buffer);182info->jframes_buffer = NULL;183}184}185186static void187cleanup_item(TableIndex index, void *key_ptr, int key_len,188void *info_ptr, void *arg)189{190TlsInfo * info;191192info = (TlsInfo*)info_ptr;193clean_info(info);194}195196static void197delete_ref_item(TableIndex index, void *key_ptr, int key_len,198void *info_ptr, void *arg)199{200delete_globalref((JNIEnv*)arg, (TlsInfo*)info_ptr);201}202203static void204list_item(TableIndex index, void *key_ptr, int key_len,205void *info_ptr, void *arg)206{207TlsInfo *info;208209HPROF_ASSERT(info_ptr!=NULL);210211info = (TlsInfo*)info_ptr;212debug_message( "Tls 0x%08x: SN=%u, sample_status=%d, agent=%d, "213"thread=%p, monitor=0x%08x, "214"tracker_status=%d\n",215index,216*(SerialNumber*)key_ptr,217info->sample_status,218info->agent_thread,219(void*)info->globalref,220info->monitor_index,221info->tracker_status);222}223224static void225search_item(TableIndex index, void *key_ptr, int key_len,226void *info_ptr, void *arg)227{228TlsInfo *info;229SearchData *data;230jobject lref;231232HPROF_ASSERT(info_ptr!=NULL);233HPROF_ASSERT(arg!=NULL);234info = (TlsInfo*)info_ptr;235data = (SearchData*)arg;236lref = newLocalReference(data->env, info->globalref);237if ( lref != NULL ) {238if ( isSameObject(data->env, data->thread, lref) ) {239HPROF_ASSERT(data->found==0); /* Did we find more than one? */240data->found = index;241}242deleteLocalReference(data->env, lref);243}244}245246static TlsIndex247search(JNIEnv *env, jthread thread)248{249SearchData data;250251HPROF_ASSERT(env!=NULL);252HPROF_ASSERT(thread!=NULL);253254data.env = env;255data.thread = thread;256data.found = 0;257table_walk_items(gdata->tls_table, &search_item, (void*)&data);258return data.found;259}260261static void262garbage_collect_item(TableIndex index, void *key_ptr, int key_len,263void *info_ptr, void *arg)264{265TlsInfo *info;266JNIEnv *env;267jobject lref;268269HPROF_ASSERT(info_ptr!=NULL);270HPROF_ASSERT(arg!=NULL);271info = (TlsInfo*)info_ptr;272env = (JNIEnv*)arg;273lref = newLocalReference(env, info->globalref);274if ( lref == NULL ) {275delete_globalref(env, info);276clean_info(info);277table_free_entry(gdata->tls_table, index);278} else {279deleteLocalReference(env, lref);280}281}282283void284tls_garbage_collect(JNIEnv *env)285{286HPROF_ASSERT(env!=NULL);287rawMonitorEnter(gdata->data_access_lock); {288table_walk_items(gdata->tls_table, &garbage_collect_item, (void*)env);289} rawMonitorExit(gdata->data_access_lock);290}291292static void293sum_sample_status_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)294{295TlsInfo *info;296297HPROF_ASSERT(info_ptr!=NULL);298info = (TlsInfo*)info_ptr;299if ( !info->agent_thread ) {300(*(jint*)arg) += info->sample_status;301}302}303304static void305setup_trace_buffers(TlsInfo *info, int max_depth)306{307int nbytes;308int max_frames;309310if ( info->frames_buffer != NULL && info->buffer_depth >= max_depth ) {311return;312}313if ( info->frames_buffer != NULL ) {314HPROF_FREE(info->frames_buffer);315}316if ( info->jframes_buffer != NULL ) {317HPROF_FREE(info->jframes_buffer);318}319info->buffer_depth = max_depth;320max_frames = max_depth + 4; /* Allow for BCI & <init> */321nbytes = (int)sizeof(FrameIndex)*(max_frames+1);322info->frames_buffer = HPROF_MALLOC(nbytes);323nbytes = (int)sizeof(jvmtiFrameInfo)*(max_frames+1);324info->jframes_buffer = HPROF_MALLOC(nbytes);325}326327static TraceIndex328get_trace(jthread thread, SerialNumber thread_serial_num,329int depth, jboolean skip_init,330FrameIndex *frames_buffer, jvmtiFrameInfo *jframes_buffer)331{332TraceIndex trace_index;333334trace_index = gdata->system_trace_index;335if ( thread != NULL ) {336trace_index = trace_get_current(thread,337thread_serial_num, depth, skip_init,338frames_buffer, jframes_buffer);339}340return trace_index;341}342343/* Find thread with certain object index */344static void345sample_setter(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)346{347TlsInfo *info;348349HPROF_ASSERT(info_ptr!=NULL);350351info = (TlsInfo*)info_ptr;352if ( info->globalref != NULL && !info->agent_thread ) {353SampleData *data;354355data = (SampleData*)arg;356if ( data->thread_object_index == info->thread_object_index ) {357info->sample_status = data->sample_status;358}359}360}361362/* Get various lists on known threads */363static void364get_thread_list(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)365{366SerialNumber thread_serial_num;367TlsInfo *info;368ThreadList *list;369jthread thread;370371HPROF_ASSERT(key_ptr!=NULL);372HPROF_ASSERT(info_ptr!=NULL);373374thread_serial_num = *(SerialNumber*)key_ptr;375info = (TlsInfo*)info_ptr;376list = (ThreadList*)arg;377thread = newLocalReference(list->env, info->globalref);378if ( thread != NULL && info->sample_status != 0 && !info->agent_thread ) {379if ( list->infos != NULL ) {380list->infos[list->count] = info;381}382if ( list->serial_nums != NULL ) {383list->serial_nums[list->count] = thread_serial_num;384}385list->threads[list->count] = thread;386list->count++;387/* Local reference gets freed by caller */388} else {389/* If we don't use the local reference, delete it now */390if ( thread != NULL ) {391deleteLocalReference(list->env, thread);392}393}394}395396static void397adjust_stats(jlong total_time, jlong self_time, TraceIndex trace_index,398StackElement *parent)399{400if ( total_time > 0 && parent != NULL ) { /* if a caller exists */401parent->time_in_callees += total_time;402}403trace_increment_cost(trace_index, 1, self_time, total_time);404}405406static void407push_method(Stack *stack, jlong method_start_time, jmethodID method)408{409StackElement new_element;410FrameIndex frame_index;411412HPROF_ASSERT(method!=NULL);413HPROF_ASSERT(stack!=NULL);414415frame_index = frame_find_or_create(method, -1);416HPROF_ASSERT(frame_index != 0);417new_element.frame_index = frame_index;418new_element.method = method;419new_element.method_start_time= method_start_time;420new_element.time_in_callees = (jlong)0;421stack_push(stack, &new_element);422}423424static Stack *425insure_method_on_stack(jthread thread, TlsInfo *info, jlong current_time,426FrameIndex frame_index, jmethodID method)427{428StackElement element;429void *p;430int depth;431int count;432int fcount;433int i;434Stack *new_stack;435Stack *stack;436437stack = info->stack;438439HPROF_ASSERT(method!=NULL);440441/* If this method is on the stack, just return */442depth = stack_depth(stack);443p = stack_top(stack);444if ( p != NULL ) {445element = *(StackElement*)p;446if ( element.frame_index == frame_index ) {447return stack;448}449}450for ( i = 0 ; i < depth ; i++ ) {451p = stack_element(stack, i);452element = *(StackElement*)p;453if ( element.frame_index == frame_index ) {454return stack;455}456}457458/* It wasn't found, create a new stack */459getFrameCount(thread, &count);460if ( count <= 0 ) {461HPROF_ERROR(JNI_FALSE, "no frames, method can't be on stack");462}463setup_trace_buffers(info, count);464getStackTrace(thread, info->jframes_buffer, count, &fcount);465HPROF_ASSERT(count==fcount);466467/* Create a new stack */468new_stack = stack_init(INITIAL_THREAD_STACK_LIMIT,469INITIAL_THREAD_STACK_LIMIT,470(int)sizeof(StackElement));471for ( i = count-1; i >= 0 ; i-- ) {472push_method(new_stack, current_time, info->jframes_buffer[i].method);473}474if ( depth > 0 ) {475for ( i = depth-1 ; i >= 0; i-- ) {476stack_push(new_stack, stack_element(stack, i));477}478}479stack_term(stack);480return new_stack;481}482483static void484pop_method(TlsIndex index, jlong current_time, jmethodID method, FrameIndex frame_index)485{486SerialNumber thread_serial_num;487TlsInfo * info;488StackElement element;489void *p;490int depth;491int trace_depth;492jlong total_time;493jlong self_time;494int i;495TraceIndex trace_index;496497HPROF_ASSERT(method!=NULL);498HPROF_ASSERT(frame_index!=0);499500thread_serial_num = get_key(index);501info = get_info(index);502HPROF_ASSERT(info!=NULL);503HPROF_ASSERT(info->stack!=NULL);504depth = stack_depth(info->stack);505p = stack_pop(info->stack);506if (p == NULL) {507HPROF_ERROR(JNI_FALSE, "method return tracked, but stack is empty");508return;509}510element = *(StackElement*)p;511HPROF_ASSERT(element.frame_index!=0);512513/* The depth of frames we should keep track for reporting */514if (gdata->prof_trace_depth > depth) {515trace_depth = depth;516} else {517trace_depth = gdata->prof_trace_depth;518}519520/* Create a trace entry */521HPROF_ASSERT(info->frames_buffer!=NULL);522HPROF_ASSERT(info->jframes_buffer!=NULL);523setup_trace_buffers(info, trace_depth);524info->frames_buffer[0] = element.frame_index;525for (i = 1; i < trace_depth; i++) {526StackElement e;527528e = *(StackElement*)stack_element(info->stack, (depth - i) - 1);529info->frames_buffer[i] = e.frame_index;530HPROF_ASSERT(e.frame_index!=0);531}532trace_index = trace_find_or_create(thread_serial_num,533trace_depth, info->frames_buffer, info->jframes_buffer);534535/* Calculate time spent */536total_time = current_time - element.method_start_time;537if ( total_time < 0 ) {538total_time = 0;539self_time = 0;540} else {541self_time = total_time - element.time_in_callees;542}543544/* Update stats */545p = stack_top(info->stack);546if ( p != NULL ) {547adjust_stats(total_time, self_time, trace_index, (StackElement*)p);548} else {549adjust_stats(total_time, self_time, trace_index, NULL);550}551}552553static void554dump_thread_state(TlsIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)555{556SerialNumber thread_serial_num;557TlsInfo *info;558jthread thread;559JNIEnv *env;560561HPROF_ASSERT(key_ptr!=NULL);562HPROF_ASSERT(info_ptr!=NULL);563env = (JNIEnv*)arg;564thread_serial_num = *(SerialNumber*)key_ptr;565info = (TlsInfo*)info_ptr;566thread = newLocalReference(env, info->globalref);567if ( thread != NULL ) {568jint threadState;569SerialNumber trace_serial_num;570571getThreadState(thread, &threadState);572/* A 0 trace at this time means the thread is in unknown territory.573* The trace serial number MUST be a valid serial number, so we use574* the system trace (empty) just so it has a valid trace.575*/576if ( info->last_trace == 0 ) {577trace_serial_num = trace_get_serial_number(gdata->system_trace_index);578} else {579trace_serial_num = trace_get_serial_number(info->last_trace);580}581io_write_monitor_dump_thread_state(thread_serial_num,582trace_serial_num, threadState);583deleteLocalReference(env, thread);584}585}586587static SerialNumber588get_serial_number(JNIEnv *env, jthread thread)589{590TlsIndex index;591592if ( thread == NULL ) {593return gdata->unknown_thread_serial_num;594}595HPROF_ASSERT(env!=NULL);596index = tls_find_or_create(env, thread);597return get_key(index);598}599600static void601dump_monitor_state(TlsIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)602{603TlsInfo *info;604jthread thread;605JNIEnv *env;606607HPROF_ASSERT(info_ptr!=NULL);608env = (JNIEnv*)arg;609info = (TlsInfo*)info_ptr;610thread = newLocalReference(env, info->globalref);611if ( thread != NULL ) {612jobject *objects;613jint ocount;614int i;615616getOwnedMonitorInfo(thread, &objects, &ocount);617if ( ocount > 0 ) {618for ( i = 0 ; i < ocount ; i++ ) {619jvmtiMonitorUsage usage;620SerialNumber *waiter_nums;621SerialNumber *notify_waiter_nums;622int t;623char * sig;624625WITH_LOCAL_REFS(env, 1) {626jclass clazz;627628clazz = getObjectClass(env, objects[i]);629getClassSignature(clazz, &sig, NULL);630} END_WITH_LOCAL_REFS;631632getObjectMonitorUsage(objects[i], &usage);633waiter_nums = HPROF_MALLOC(usage.waiter_count*634(int)sizeof(SerialNumber)+1);635for ( t = 0 ; t < usage.waiter_count ; t++ ) {636waiter_nums[t] =637get_serial_number(env, usage.waiters[t]);638}639notify_waiter_nums = HPROF_MALLOC(usage.notify_waiter_count*640(int)sizeof(SerialNumber)+1);641for ( t = 0 ; t < usage.notify_waiter_count ; t++ ) {642notify_waiter_nums[t] =643get_serial_number(env, usage.notify_waiters[t]);644}645io_write_monitor_dump_state(sig,646get_serial_number(env, usage.owner),647usage.entry_count,648waiter_nums, usage.waiter_count,649notify_waiter_nums, usage.notify_waiter_count);650jvmtiDeallocate(sig);651jvmtiDeallocate(usage.waiters);652jvmtiDeallocate(usage.notify_waiters);653HPROF_FREE(waiter_nums);654HPROF_FREE(notify_waiter_nums);655}656}657jvmtiDeallocate(objects);658deleteLocalReference(env, thread);659}660}661662static jlong663monitor_time(void)664{665jlong mtime;666667mtime = md_get_timemillis(); /* gettimeofday() */668return mtime;669}670671static jlong672method_time(void)673{674jlong method_time;675676method_time = md_get_thread_cpu_timemillis(); /* thread CPU time */677return method_time;678}679680/* External interfaces */681682TlsIndex683tls_find_or_create(JNIEnv *env, jthread thread)684{685SerialNumber thread_serial_num;686static TlsInfo empty_info;687TlsInfo info;688TlsIndex index;689690HPROF_ASSERT(env!=NULL);691HPROF_ASSERT(thread!=NULL);692693/*LINTED*/694index = (TlsIndex)(ptrdiff_t)getThreadLocalStorage(thread);695if ( index != 0 ) {696HPROF_ASSERT(isSameObject(env, thread, get_info(index)->globalref));697return index;698}699index = search(env, thread);700if ( index != 0 ) {701setThreadLocalStorage(thread, (void*)(ptrdiff_t)index);702return index;703}704thread_serial_num = gdata->thread_serial_number_counter++;705info = empty_info;706info.monitor_index = 0;707info.sample_status = 1;708info.agent_thread = JNI_FALSE;709info.stack = stack_init(INITIAL_THREAD_STACK_LIMIT,710INITIAL_THREAD_STACK_LIMIT,711(int)sizeof(StackElement));712setup_trace_buffers(&info, gdata->max_trace_depth);713info.globalref = newWeakGlobalReference(env, thread);714index = table_create_entry(gdata->tls_table, &thread_serial_num, (int)sizeof(SerialNumber), (void*)&info);715setThreadLocalStorage(thread, (void*)(ptrdiff_t)index);716HPROF_ASSERT(search(env,thread)==index);717return index;718}719720/* Mark a new or existing entry as being an agent thread */721void722tls_agent_thread(JNIEnv *env, jthread thread)723{724TlsIndex index;725TlsInfo *info;726727index = tls_find_or_create(env, thread);728info = get_info(index);729info->agent_thread = JNI_TRUE;730}731732void733tls_init(void)734{735gdata->tls_table = table_initialize("TLS",73616, 16, 16, (int)sizeof(TlsInfo));737}738739void740tls_list(void)741{742debug_message(743"--------------------- TLS Table ------------------------\n");744table_walk_items(gdata->tls_table, &list_item, NULL);745debug_message(746"----------------------------------------------------------\n");747}748749jint750tls_sum_sample_status(void)751{752jint sample_status_total;753754sample_status_total = 0;755table_walk_items(gdata->tls_table, &sum_sample_status_item, (void*)&sample_status_total);756return sample_status_total;757}758759void760tls_set_sample_status(ObjectIndex object_index, jint sample_status)761{762SampleData data;763764data.thread_object_index = object_index;765data.sample_status = sample_status;766table_walk_items(gdata->tls_table, &sample_setter, (void*)&data);767}768769jint770tls_get_tracker_status(JNIEnv *env, jthread thread, jboolean skip_init,771jint **ppstatus, TlsIndex* pindex,772SerialNumber *pthread_serial_num, TraceIndex *ptrace_index)773{774TlsInfo *info;775TlsIndex index;776SerialNumber thread_serial_num;777jint status;778779index = tls_find_or_create(env, thread);780info = get_info(index);781*ppstatus = &(info->tracker_status);782status = **ppstatus;783thread_serial_num = get_key(index);784785if ( pindex != NULL ) {786*pindex = index;787}788if ( status != 0 ) {789return status;790}791if ( ptrace_index != NULL ) {792setup_trace_buffers(info, gdata->max_trace_depth);793*ptrace_index = get_trace(thread, thread_serial_num,794gdata->max_trace_depth, skip_init,795info->frames_buffer, info->jframes_buffer);796}797if ( pthread_serial_num != NULL ) {798*pthread_serial_num = thread_serial_num;799}800return status;801}802803MonitorIndex804tls_get_monitor(TlsIndex index)805{806TlsInfo *info;807808info = get_info(index);809return info->monitor_index;810}811812void813tls_set_thread_object_index(TlsIndex index, ObjectIndex thread_object_index)814{815TlsInfo *info;816817info = get_info(index);818info->thread_object_index = thread_object_index;819}820821SerialNumber822tls_get_thread_serial_number(TlsIndex index)823{824return get_key(index);825}826827void828tls_set_monitor(TlsIndex index, MonitorIndex monitor_index)829{830TlsInfo *info;831832info = get_info(index);833info->monitor_index = monitor_index;834}835836void837tls_cleanup(void)838{839table_cleanup(gdata->tls_table, &cleanup_item, NULL);840gdata->tls_table = NULL;841}842843void844tls_delete_global_references(JNIEnv *env)845{846table_walk_items(gdata->tls_table, &delete_ref_item, (void*)env);847}848849void850tls_thread_ended(JNIEnv *env, TlsIndex index)851{852HPROF_ASSERT(env!=NULL);853854/* Sample thread stack for last time, do NOT free the entry yet. */855table_lock_enter(gdata->tls_table); {856SerialNumber thread_serial_num;857TlsInfo *info;858jthread thread;859860thread_serial_num = get_key(index);861info = get_info(index);862thread = newLocalReference(env, info->globalref);863if (gdata->heap_dump && thread!=NULL) {864setup_trace_buffers(info, gdata->max_trace_depth);865info->last_trace = get_trace(thread, thread_serial_num,866gdata->max_trace_depth, JNI_FALSE,867info->frames_buffer, info->jframes_buffer);868}869if ( thread != NULL ) {870deleteLocalReference(env, thread);871}872} table_lock_exit(gdata->tls_table);873874}875876/* Sample ALL threads and update the trace costs */877void878tls_sample_all_threads(JNIEnv *env)879{880ThreadList list;881jthread *threads;882SerialNumber *serial_nums;883884table_lock_enter(gdata->tls_table); {885int max_count;886int nbytes;887int i;888889/* Get buffers to hold thread list and serial number list */890max_count = table_element_count(gdata->tls_table);891nbytes = (int)sizeof(jthread)*max_count;892threads = (jthread*)HPROF_MALLOC(nbytes);893nbytes = (int)sizeof(SerialNumber)*max_count;894serial_nums = (SerialNumber*)HPROF_MALLOC(nbytes);895896/* Get list of threads and serial numbers */897list.threads = threads;898list.infos = NULL;899list.serial_nums = serial_nums;900list.count = 0;901list.env = env;902table_walk_items(gdata->tls_table, &get_thread_list, (void*)&list);903904/* Increment the cost on the traces for these threads */905trace_increment_all_sample_costs(list.count, threads, serial_nums,906gdata->max_trace_depth, JNI_FALSE);907908/* Loop over local refs and free them */909for ( i = 0 ; i < list.count ; i++ ) {910if ( threads[i] != NULL ) {911deleteLocalReference(env, threads[i]);912}913}914915} table_lock_exit(gdata->tls_table);916917/* Free up allocated space */918HPROF_FREE(threads);919HPROF_FREE(serial_nums);920921}922923void924tls_push_method(TlsIndex index, jmethodID method)925{926jlong method_start_time;927TlsInfo *info;928929HPROF_ASSERT(method!=NULL);930info = get_info(index);931HPROF_ASSERT(info!=NULL);932method_start_time = method_time();933HPROF_ASSERT(info->stack!=NULL);934push_method(info->stack, method_start_time, method);935}936937void938tls_pop_exception_catch(TlsIndex index, jthread thread, jmethodID method)939{940TlsInfo *info;941StackElement element;942void *p;943FrameIndex frame_index;944jlong current_time;945946HPROF_ASSERT(method!=NULL);947frame_index = frame_find_or_create(method, -1);948HPROF_ASSERT(frame_index != 0);949950info = get_info(index);951952HPROF_ASSERT(info!=NULL);953HPROF_ASSERT(info->stack!=NULL);954HPROF_ASSERT(frame_index!=0);955current_time = method_time();956info->stack = insure_method_on_stack(thread, info, current_time,957frame_index, method);958p = stack_top(info->stack);959if (p == NULL) {960HPROF_ERROR(JNI_FALSE, "expection pop, nothing on stack");961return;962}963element = *(StackElement*)p;964HPROF_ASSERT(element.frame_index!=0);965while ( element.frame_index != frame_index ) {966pop_method(index, current_time, element.method, frame_index);967p = stack_top(info->stack);968if ( p == NULL ) {969break;970}971element = *(StackElement*)p;972}973if (p == NULL) {974HPROF_ERROR(JNI_FALSE, "exception pop stack empty");975}976}977978void979tls_pop_method(TlsIndex index, jthread thread, jmethodID method)980{981TlsInfo *info;982StackElement element;983void *p;984FrameIndex frame_index;985jlong current_time;986987HPROF_ASSERT(method!=NULL);988frame_index = frame_find_or_create(method, -1);989HPROF_ASSERT(frame_index != 0);990991info = get_info(index);992HPROF_ASSERT(info!=NULL);993HPROF_ASSERT(info->stack!=NULL);994current_time = method_time();995HPROF_ASSERT(frame_index!=0);996info->stack = insure_method_on_stack(thread, info, current_time,997frame_index, method);998p = stack_top(info->stack);999HPROF_ASSERT(p!=NULL);1000element = *(StackElement*)p;1001while ( element.frame_index != frame_index ) {1002pop_method(index, current_time, element.method, frame_index);1003p = stack_top(info->stack);1004if ( p == NULL ) {1005break;1006}1007element = *(StackElement*)p;1008}1009pop_method(index, current_time, method, frame_index);1010}10111012/* For all TLS entries, update the last_trace on all threads */1013static void1014update_all_last_traces(JNIEnv *env)1015{1016jthread *threads;1017TlsInfo **infos;1018SerialNumber *serial_nums;1019TraceIndex *traces;10201021if ( gdata->max_trace_depth == 0 ) {1022return;1023}10241025table_lock_enter(gdata->tls_table); {10261027ThreadList list;1028int max_count;1029int nbytes;1030int i;10311032/* Get buffers to hold thread list and serial number list */1033max_count = table_element_count(gdata->tls_table);1034nbytes = (int)sizeof(jthread)*max_count;1035threads = (jthread*)HPROF_MALLOC(nbytes);1036nbytes = (int)sizeof(SerialNumber)*max_count;1037serial_nums = (SerialNumber*)HPROF_MALLOC(nbytes);1038nbytes = (int)sizeof(TlsInfo*)*max_count;1039infos = (TlsInfo**)HPROF_MALLOC(nbytes);10401041/* Get list of threads, serial numbers, and info pointers */1042list.threads = threads;1043list.serial_nums = serial_nums;1044list.infos = infos;1045list.count = 0;1046list.env = env;1047table_walk_items(gdata->tls_table, &get_thread_list, (void*)&list);10481049/* Get all stack trace index's for all these threadss */1050nbytes = (int)sizeof(TraceIndex)*max_count;1051traces = (TraceIndex*)HPROF_MALLOC(nbytes);1052trace_get_all_current(list.count, threads, serial_nums,1053gdata->max_trace_depth, JNI_FALSE,1054traces, JNI_TRUE);10551056/* Loop over traces and update last_trace's */1057for ( i = 0 ; i < list.count ; i++ ) {1058if ( threads[i] != NULL ) {1059deleteLocalReference(env, threads[i]);1060}1061infos[i]->last_trace = traces[i];1062}10631064} table_lock_exit(gdata->tls_table);10651066/* Free up all allocated space */1067HPROF_FREE(threads);1068HPROF_FREE(serial_nums);1069HPROF_FREE(infos);1070HPROF_FREE(traces);10711072}10731074void1075tls_dump_traces(JNIEnv *env)1076{1077rawMonitorEnter(gdata->data_access_lock); {1078update_all_last_traces(env);1079trace_output_unmarked(env);1080} rawMonitorExit(gdata->data_access_lock);1081}10821083void1084tls_dump_monitor_state(JNIEnv *env)1085{1086HPROF_ASSERT(env!=NULL);10871088rawMonitorEnter(gdata->data_access_lock); {1089tls_dump_traces(env);1090io_write_monitor_dump_header();1091table_walk_items(gdata->tls_table, &dump_thread_state, (void*)env);1092table_walk_items(gdata->tls_table, &dump_monitor_state, (void*)env);1093io_write_monitor_dump_footer();1094} rawMonitorExit(gdata->data_access_lock);1095}10961097void1098tls_monitor_start_timer(TlsIndex index)1099{1100TlsInfo *info;11011102info = get_info(index);1103HPROF_ASSERT(info!=NULL);1104HPROF_ASSERT(info->globalref!=NULL);1105info->monitor_start_time = monitor_time();1106}11071108jlong1109tls_monitor_stop_timer(TlsIndex index)1110{1111TlsInfo *info;1112jlong t;11131114info = get_info(index);1115HPROF_ASSERT(info!=NULL);1116t = monitor_time() - info->monitor_start_time;1117info->monitor_start_time = 0;1118return t;1119}11201121TraceIndex1122tls_get_trace(TlsIndex index, JNIEnv *env, int depth, jboolean skip_init)1123{1124SerialNumber thread_serial_num;1125TraceIndex trace_index;1126TlsInfo *info;1127jthread thread;11281129thread_serial_num = get_key(index);1130info = get_info(index);1131HPROF_ASSERT(info!=NULL);1132setup_trace_buffers(info, depth);1133thread = newLocalReference(env, info->globalref);1134if ( thread != NULL ) {1135trace_index = get_trace(thread, thread_serial_num, depth, skip_init,1136info->frames_buffer, info->jframes_buffer);1137deleteLocalReference(env, thread);1138} else {1139trace_index = gdata->system_trace_index;1140}1141return trace_index;1142}11431144void1145tls_set_in_heap_dump(TlsIndex index, jint in_heap_dump)1146{1147TlsInfo *info;11481149info = get_info(index);1150info->in_heap_dump = in_heap_dump;1151}11521153jint1154tls_get_in_heap_dump(TlsIndex index)1155{1156TlsInfo *info;11571158info = get_info(index);1159return info->in_heap_dump;1160}11611162static void1163clean_in_heap_dump(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)1164{1165TlsInfo *info;11661167HPROF_ASSERT(info_ptr!=NULL);1168info = (TlsInfo*)info_ptr;1169info->in_heap_dump = 0;1170}11711172void1173tls_clear_in_heap_dump(void)1174{1175table_walk_items(gdata->tls_table, &clean_in_heap_dump, NULL);1176}11771178TlsIndex1179tls_find(SerialNumber thread_serial_num)1180{1181TlsIndex index;11821183if ( thread_serial_num == 0 ) {1184return 0;1185}1186index = table_find_entry(gdata->tls_table,1187(void*)&thread_serial_num, (int)sizeof(SerialNumber));1188return index;1189}119011911192