hprof_listener.c

来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 434 行

C
434
字号
/* * @(#)hprof_listener.c	1.19 05/11/17 *  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: *  * -Redistribution of source code must retain the above copyright notice, this *  list of conditions and the following disclaimer. *  * -Redistribution in binary form must reproduce the above copyright notice,  *  this list of conditions and the following disclaimer in the documentation *  and/or other materials provided with the distribution. *  * Neither the name of Sun Microsystems, Inc. or the names of contributors may  * be used to endorse or promote products derived from this software without  * specific prior written permission. *  * This software is provided "AS IS," without a warranty of any kind. ALL  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. *  * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. *//* The hprof listener loop thread. net=hostname:port option *//* * The option net=hostname:port causes all hprof output to be sent down *   a socket connection, and also allows for commands to come in over the *   socket. The commands are documented below. * * This thread can cause havoc when started prematurely or not terminated *   properly, see listener_init() and listener_term(), and their calls  *   in hprof_init.c. * * The listener loop (hprof_listener.c) can dynamically turn on or off the *  sampling of all or selected threads. * * The specification of this command protocol is only here, in the comments *  below.  The HAT tools uses this interface. *  It is also unknown how well these options work given the limited *  testing of this interface. * */#include "hprof.h"/* When the hprof Agent in the VM is connected via a socket to the  * profiling client, the client may send the hprof Agent a set of commands.  * The commands have the following format: * * u1		a TAG denoting the type of the record * u4		a serial number * u4		number of bytes *remaining* in the record. Note that *		this number excludes the tag and the length field itself. * [u1]*	BODY of the record (a sequence of bytes) *//* The following commands are presently supported: * * TAG		 BODY	    notes * ---------------------------------------------------------- * HPROF_CMD_GC		    force a GC. * * HPROF_CMD_DUMP_HEAP	    obtain a heap dump * * HPROF_CMD_ALLOC_SITES    obtain allocation sites * *		 u2	    flags 0x0001: incremental vs. complete *				  0x0002: sorted by allocation vs. live *				  0x0004: whether to force a GC *		 u4	    cutoff ratio (0.0 ~ 1.0) * * HPROF_CMD_HEAP_SUMMARY   obtain heap summary * * HPROF_CMD_DUMP_TRACES    obtain all newly created traces * * HPROF_CMD_CPU_SAMPLES    obtain a HPROF_CPU_SAMPLES record * *		 u2	    ignored for now *		 u4	    cutoff ratio (0.0 ~ 1.0) * * HPROF_CMD_CONTROL	    changing settings * *		 u2	    0x0001: alloc traces on *                          0x0002: alloc traces off * *                          0x0003: CPU sampling on * *                                  id:	  thread object id (NULL for all) * *                          0x0004: CPU sampling off * *                                  id:	  thread object id (NULL for all) * *                          0x0005: CPU sampling clear * *                          0x0006: clear alloc sites info * *                          0x0007: set max stack depth in CPU samples *                                  and alloc traces * *                                  u2:	  new depth */typedef enum HprofCmd {    HPROF_CMD_GC		= 0x01,    HPROF_CMD_DUMP_HEAP     	= 0x02,    HPROF_CMD_ALLOC_SITES   	= 0x03,    HPROF_CMD_HEAP_SUMMARY  	= 0x04,    HPROF_CMD_EXIT		= 0x05,    HPROF_CMD_DUMP_TRACES   	= 0x06,    HPROF_CMD_CPU_SAMPLES   	= 0x07,    HPROF_CMD_CONTROL		= 0x08,    HPROF_CMD_EOF 		= 0xFF} HprofCmd;static jint recv_fully(int f, char *buf, int len){    jint nbytes;        nbytes = 0;    if ( f < 0 ) {	return nbytes;    }    while (nbytes < len) {        int res;                res = md_recv(f, buf + nbytes, (len - nbytes), 0);        if (res < 0) {            /*             * hprof was disabled before we returned from recv() above.             * This means the command socket is closed so we let that             * trickle back up the command processing stack.             */            LOG("recv() returned < 0");	    break;        }        nbytes += res;    }    return nbytes;}static unsigned char recv_u1(void){    unsigned char c;    jint nbytes;        nbytes = recv_fully(gdata->fd, (char *)&c, (int)sizeof(unsigned char));    if (nbytes == 0) {        c = HPROF_CMD_EOF;    }    return c;}static unsigned short recv_u2(void){    unsigned short s;    jint nbytes;        nbytes = recv_fully(gdata->fd, (char *)&s, (int)sizeof(unsigned short));    if (nbytes == 0) {        s = (unsigned short)-1;    }    return md_ntohs(s);}static unsignedrecv_u4(void){    unsigned i;    jint nbytes;        nbytes = recv_fully(gdata->fd, (char *)&i, (int)sizeof(unsigned));    if (nbytes == 0) {        i = (unsigned)-1;    }    return md_ntohl(i);}static ObjectIndexrecv_id(void){    ObjectIndex result;    jint        nbytes;        nbytes = recv_fully(gdata->fd, (char *)&result, (int)sizeof(ObjectIndex));    if (nbytes == 0) {        result = (ObjectIndex)0;    }    return result;}static void JNICALLlistener_loop_function(jvmtiEnv *jvmti, JNIEnv *env, void *p){    jboolean keep_processing;    unsigned char tag;    jboolean kill_the_whole_process;    kill_the_whole_process = JNI_FALSE;    tag = 0;        rawMonitorEnter(gdata->listener_loop_lock); {        gdata->listener_loop_running = JNI_TRUE;        keep_processing = gdata->listener_loop_running;	/* Tell listener_init() that we have started */	rawMonitorNotifyAll(gdata->listener_loop_lock);    } rawMonitorExit(gdata->listener_loop_lock);        while ( keep_processing ) {	LOG("listener loop iteration");        	tag = recv_u1();  /* This blocks here on the socket read, a close()			   *   on this fd will wake this up. And if recv_u1()			   *   can't read anything, it returns HPROF_CMD_EOF.			   */	LOG3("listener_loop", "command = ", tag);        	if (tag == HPROF_CMD_EOF) {            /* The cmd socket has closed so the listener thread is done 	     *   just fall out of loop and let the thread die.	     */	    keep_processing = JNI_FALSE;            break;        }		/* seq_num not used */	(void)recv_u4();	/* length not used */        (void)recv_u4();        switch (tag) {            case HPROF_CMD_GC:                runGC();                break;            case HPROF_CMD_DUMP_HEAP: {                site_heapdump(env);                break;            }            case HPROF_CMD_ALLOC_SITES: {                unsigned short flags;                unsigned i_tmp;                float ratio;                		flags = recv_u2();                i_tmp = recv_u4();                ratio = *(float *)(&i_tmp);                site_write(env, flags, ratio);                break;            }            case HPROF_CMD_HEAP_SUMMARY: {                rawMonitorEnter(gdata->data_access_lock); {                    io_write_heap_summary(  gdata->total_live_bytes,                                            gdata->total_live_instances,                                            gdata->total_alloced_bytes,                                            gdata->total_alloced_instances);                } rawMonitorExit(gdata->data_access_lock);                break;            }            case HPROF_CMD_EXIT:                keep_processing = JNI_FALSE;                kill_the_whole_process = JNI_TRUE;                verbose_message("HPROF: received exit event, exiting ...\n");                break;            case HPROF_CMD_DUMP_TRACES:                rawMonitorEnter(gdata->data_access_lock); {                    trace_output_unmarked(env);                } rawMonitorExit(gdata->data_access_lock);                break;            case HPROF_CMD_CPU_SAMPLES: {                unsigned i_tmp;                float ratio;				/* flags not used */		(void)recv_u2();                i_tmp = recv_u4();                ratio = *(float *)(&i_tmp);                trace_output_cost(env, ratio);                break;            }            case HPROF_CMD_CONTROL: {                unsigned short cmd = recv_u2();                if (cmd == 0x0001) {                    setEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL);                     tracker_engage(env);                } else if (cmd == 0x0002) {                    setEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_OBJECT_FREE, NULL);                    tracker_disengage(env);                } else if (cmd == 0x0003) {                    ObjectIndex thread_object_index;                    thread_object_index = recv_id();                     cpu_sample_on(env, thread_object_index);                } else if (cmd == 0x0004) {                    ObjectIndex thread_object_index;                    thread_object_index = recv_id();                     cpu_sample_off(env, thread_object_index);                } else if (cmd == 0x0005) {                    rawMonitorEnter(gdata->data_access_lock); {                        trace_clear_cost();                    } rawMonitorExit(gdata->data_access_lock);                } else if (cmd == 0x0006) {                    rawMonitorEnter(gdata->data_access_lock); {                        site_cleanup();                        site_init();                    } rawMonitorExit(gdata->data_access_lock);                } else if (cmd == 0x0007) {                    gdata->max_trace_depth = recv_u2();                }                break;            }            default:{                char buf[80];		                keep_processing = JNI_FALSE;                kill_the_whole_process = JNI_TRUE;		(void)md_snprintf(buf, sizeof(buf),			"failed to recognize cmd %d, exiting..", (int)tag);		buf[sizeof(buf)-1] = 0;		HPROF_ERROR(JNI_FALSE, buf);                break;            }        }        	rawMonitorEnter(gdata->data_access_lock); {            io_flush();        } rawMonitorExit(gdata->data_access_lock);        	rawMonitorEnter(gdata->listener_loop_lock); {	    if ( !gdata->listener_loop_running ) {		keep_processing 	= JNI_FALSE;	    }        } rawMonitorExit(gdata->listener_loop_lock);        }       /* If listener_term() is causing this loop to terminate, then     *   you will block here until listener_term wants you to proceed.     */    rawMonitorEnter(gdata->listener_loop_lock); {	if ( gdata->listener_loop_running ) {	    /* We are terminating for our own reasons, maybe because of 	     *   EOF (socket closed?), or EXIT request, or invalid command.	     *   Not from listener_term().	     *   We set gdata->listener_loop_running=FALSE so that any	     *   future call to listener_term() will do nothing.	     */	    gdata->listener_loop_running = JNI_FALSE;        } else {	    /* We assume that listener_term() is stopping us,	     *    now we need to tell it we understood.	     */	    rawMonitorNotifyAll(gdata->listener_loop_lock);        }    } rawMonitorExit(gdata->listener_loop_lock);        LOG3("listener_loop", "finished command = ", tag);       /* If we got an explicit command request to die, die here */    if ( kill_the_whole_process ) {        error_exit_process(0);    }}/* External functions */voidlistener_init(JNIEnv *env){    /* Create the raw monitor */    gdata->listener_loop_lock = createRawMonitor("HPROF listener lock");        rawMonitorEnter(gdata->listener_loop_lock); {	createAgentThread(env, "HPROF listener thread",				&listener_loop_function);	/* Wait for listener_loop_function() to tell us it started. */	rawMonitorWait(gdata->listener_loop_lock, 0);    } rawMonitorExit(gdata->listener_loop_lock);}voidlistener_term(JNIEnv *env){    rawMonitorEnter(gdata->listener_loop_lock); {	/* If we are in the middle of sending bytes down the socket, this	 *   at least keeps us blocked until that processing is done.	 */	rawMonitorEnter(gdata->data_access_lock); {           	    /* Make sure the socket gets everything */	    io_flush();	    	    /*	     * Graceful shutdown of the socket will assure that all data	     * sent is received before the socket close completes.	     */	    (void)md_shutdown(gdata->fd, 2 /* disallow sends and receives */);	    /* This close will cause the listener loop to possibly wake up	     *    from the recv_u1(), this is critical to get thread running again.	     */	    md_close(gdata->fd);	} rawMonitorExit(gdata->data_access_lock);	/* It could have shut itself down, so we check the global flag */	if ( gdata->listener_loop_running ) {	    /* It stopped because of something listener_term() did. */	    gdata->listener_loop_running = JNI_FALSE;	    /* Wait for listener_loop_function() to tell us it finished. */	    rawMonitorWait(gdata->listener_loop_lock, 0);	}    } rawMonitorExit(gdata->listener_loop_lock);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?